如何使用java.util.Scanner从System.in正确读取用户输入并对其执行操作?

如何使用java.util.Scanner从System.in正确读取用户输入并对其执行操作?,java,java.util.scanner,system.in,Java,Java.util.scanner,System.in,这是一个标准问题/答案,可以用作 重复目标。这些要求基于最常见的 每天发布的问题,可根据需要添加到。他们都 需要相同的基本代码结构才能访问每个场景 它们通常相互依赖 Scanner看起来是一个“简单”的类,这就是第一个错误的地方。它并不简单,它有各种不明显的副作用和异常行为,以非常微妙的方式打破了最小惊讶原则 这对这门课来说似乎有些过分,但是剥洋葱的错误和问题都很简单,但是综合起来,它们非常复杂,因为它们之间的相互作用和副作用。这就是为什么每天都有那么多关于堆栈溢出的问题 常见扫描仪问题: 大

这是一个标准问题/答案,可以用作 重复目标。这些要求基于最常见的 每天发布的问题,可根据需要添加到。他们都 需要相同的基本代码结构才能访问每个场景 它们通常相互依赖


Scanner看起来是一个“简单”的类,这就是第一个错误的地方。它并不简单,它有各种不明显的副作用和异常行为,以非常微妙的方式打破了最小惊讶原则

这对这门课来说似乎有些过分,但是剥洋葱的错误和问题都很简单,但是综合起来,它们非常复杂,因为它们之间的相互作用和副作用。这就是为什么每天都有那么多关于堆栈溢出的问题

常见扫描仪问题: 大多数
Scanner
问题都包括在以上一个方面的失败尝试

  • 我希望我的程序能够在每次输入之后自动等待下一次输入

  • 我想知道如何检测退出命令并在输入该命令时结束程序

  • 我想知道如何以不区分大小写的方式为exit命令匹配多个命令

  • 我希望能够匹配正则表达式模式以及内置原语。例如,如何匹配日期(
    2014/10/18

  • 我想知道如何匹配正则表达式匹配可能不容易实现的内容-例如,URL(
    http://google.com

  • 动机: 在Java世界中,
    Scanner
    是一个特例,这是一门极其挑剔的课程,老师不应该给新生使用的指导。在大多数情况下,教师甚至不知道如何正确使用它。它几乎从未在专业生产代码中使用过,因此它对学生的价值是非常值得怀疑的

    使用
    Scanner
    意味着这个问题和答案提到的所有其他事情。它绝不仅仅是关于
    扫描仪
    的问题,而是关于如何解决
    扫描仪
    的这些常见问题,这些问题在几乎所有的
    扫描仪
    出错的问题中都是共病问题。它绝不仅仅是关于,这只是类实现挑剔的一个症状,代码中总是有其他问题,在询问
    Scanner
    的问题中

    答案显示了99%使用
    Scanner
    并询问有关StackOverflow的情况的完整、惯用的实现

    尤其是在初学者代码中。如果你认为这个答案太复杂,那么在解释其行为的复杂性、怪癖、不明显的副作用和特点之前,先向指导老师投诉,让新生使用
    扫描仪

    Scanner
    是一个很好的教学时刻,它告诉我们在命名方法和方法参数时,一致的行为和语义有多重要,以及为什么一致的行为和语义很重要

    学生须知: 您可能永远不会真正看到在中使用的
    扫描仪
    专业/商业业务线应用程序,因为它 做其他事情做得更好。现实世界的软件必须 比
    扫描仪
    更具弹性和可维护性 代码。真实世界的软件使用标准化的文件格式解析器和 文件格式,而不是您正在使用的特殊输入格式 在独立作业中给出

    惯用的例子: <> >如何正确使用< C++ > java .UTI.Spults类来交互式地读取<代码>系统中的用户输入。在正确(有时称为代码> STDIN < /代码>,特别是在C、C++和其他语言以及UNIX和Linux中)。它惯用地演示了需要完成的最常见的事情

    package com.stackoverflow.scanner;
    
    import javax.annotation.Nonnull;
    import java.math.BigInteger;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.*;
    import java.util.regex.Pattern;
    
    import static java.lang.String.format;
    
    public class ScannerExample
    {
        private static final Set<String> EXIT_COMMANDS;
        private static final Set<String> HELP_COMMANDS;
        private static final Pattern DATE_PATTERN;
        private static final String HELP_MESSAGE;
    
        static
        {
            final SortedSet<String> ecmds = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
            ecmds.addAll(Arrays.asList("exit", "done", "quit", "end", "fino"));
            EXIT_COMMANDS = Collections.unmodifiableSortedSet(ecmds);
            final SortedSet<String> hcmds = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
            hcmds.addAll(Arrays.asList("help", "helpi", "?"));
            HELP_COMMANDS = Collections.unmodifiableSet(hcmds);
            DATE_PATTERN = Pattern.compile("\\d{4}([-\\/])\\d{2}\\1\\d{2}"); // http://regex101.com/r/xB8dR3/1
            HELP_MESSAGE = format("Please enter some data or enter one of the following commands to exit %s", EXIT_COMMANDS);
        }
    
        /**
         * Using exceptions to control execution flow is always bad.
         * That is why this is encapsulated in a method, this is done this
         * way specifically so as not to introduce any external libraries
         * so that this is a completely self contained example.
         * @param s possible url
         * @return true if s represents a valid url, false otherwise
         */
        private static boolean isValidURL(@Nonnull final String s)
        {
            try { new URL(s); return true; }
            catch (final MalformedURLException e) { return false; }
        }
    
        private static void output(@Nonnull final String format, @Nonnull final Object... args)
        {
            System.out.println(format(format, args));
        }
    
        public static void main(final String[] args)
        {
            final Scanner sis = new Scanner(System.in);
            output(HELP_MESSAGE);
            while (sis.hasNext())
            {
                if (sis.hasNextInt())
                {
                    final int next = sis.nextInt();
                    output("You entered an Integer = %d", next);
                }
                else if (sis.hasNextLong())
                {
                    final long next = sis.nextLong();
                    output("You entered a Long = %d", next);
                }
                else if (sis.hasNextDouble())
                {
                    final double next = sis.nextDouble();
                    output("You entered a Double = %f", next);
                }
                else if (sis.hasNext("\\d+"))
                {
                    final BigInteger next = sis.nextBigInteger();
                    output("You entered a BigInteger = %s", next);
                }
                else if (sis.hasNextBoolean())
                {
                    final boolean next = sis.nextBoolean();
                    output("You entered a Boolean representation = %s", next);
                }
                else if (sis.hasNext(DATE_PATTERN))
                {
                    final String next = sis.next(DATE_PATTERN);
                    output("You entered a Date representation = %s", next);
                }
                else // unclassified
                {
                    final String next = sis.next();
                    if (isValidURL(next))
                    {
                        output("You entered a valid URL = %s", next);
                    }
                    else
                    {
                        if (EXIT_COMMANDS.contains(next))
                        {
                            output("Exit command %s issued, exiting!", next);
                            break;
                        }
                        else if (HELP_COMMANDS.contains(next)) { output(HELP_MESSAGE); }
                        else { output("You entered an unclassified String = %s", next); }
                    }
                }
            }
            /*
               This will close the underlying InputStream, in this case System.in, and free those resources.
               WARNING: You will not be able to read from System.in anymore after you call .close().
               If you wanted to use System.in for something else, then don't close the Scanner.
            */
            sis.close();
            System.exit(0);
        }
    }
    
    package com.stackoverflow.scanner;
    导入javax.annotation.Nonnull;
    导入java.math.biginger;
    导入java.net.MalformedURLException;
    导入java.net.URL;
    导入java.util.*;
    导入java.util.regex.Pattern;
    导入静态java.lang.String.format;
    公共类扫描程序示例
    {
    专用静态最终设置退出命令;
    专用静态最终设置帮助_命令;
    私有静态最终模式日期\模式;
    私有静态最终字符串帮助_消息;
    静止的
    {
    最终分类集ecmds=新树集(字符串不区分大小写顺序);
    addAll(Arrays.asList(“exit”、“done”、“quit”、“end”、“fino”));
    EXIT_COMMANDS=Collections.unmodifiableSortedSet(ecmds);
    最终分拣集hcmds=新的树集(字符串不区分大小写\u顺序);
    addAll(Arrays.asList(“help”、“helpi”和“?”));
    HELP\u COMMANDS=Collections.unmodifiableSet(hcmds);
    DATE\u PATTERN=PATTERN.compile(“\\d{4}([-\\/])\\d{2}\\1\\d{2}”);//http://regex101.com/r/xB8dR3/1
    HELP_MESSAGE=format(“请输入一些数据或输入以下命令之一以退出%s”,退出_命令);
    }
    /**
    *使用异常来控制执行流总是不好的。
    *这就是为什么它被封装在一个方法中,这是这样做的
    *以避免引入任何外部库
    *所以这是一个完全独立的例子。
    *@param的可能url
    *@如果s表示有效url,则返回true,否则返回false
    */
    私有静态布尔值isValidURL(@Nonnull final String s)
    {
    尝试{新URL;返回true;}
    catch(final malformedurexception e){return false;}
    }
    私有静态无效输出(@Nonnull最终字符串格式,@Nonnull最终对象…args)
    {
    System.out.println(格式(format,args));
    }