如何使用java.util.Scanner正确读取System.in中的用户输入并对其进行操作?
This is meant to be a canonical question/answer that can be used as a
duplicate target. These requirements are based on the most common
questions posted every day and may be added to as needed. They all
require the same basic code structure to get to each of the scenarios
and they are generally dependent on one another.
扫描仪看起来像一个“简单”的类,这是第一个错误的地方.它并不简单,它具有各种非明显的副作用和异常行为,以非常微妙的方式打破了最小惊讶原则.
所以这对于这个课程来说似乎有些过分,但洋葱错误和问题的剥离都很简单,但由于它们的相互作用和副作用,它们非常复杂.这就是为什么每天在Stack Overflow上有很多关于它的问题.
常见扫描仪问题:
大多数扫描仪问题包括多次尝试失败.
>我希望能够让我的程序在每次上一次输入后自动等待下一个输入.>我想知道如何检测退出命令并在输入该命令时结束我的程序.>我想知道如何以不区分大小写的方式匹配exit命令的多个命令.>我希望能够匹配正则表达式模式以及内置基元.例如,如何匹配似乎是日期(2014/10/18)?>我想知道如何匹配可能无法通过正则表达式匹配实现的内容 – 例如,URL(http://google.com).
动机:
在Java世界中,Scanner是一个特例,它是一个非常挑剔的课程,教师不应该给新学生使用说明.在大多数情况下,教师甚至不知道如何正确使用它.如果在专业的生产规范中使用它几乎没有,所以它对学生的价值是非常值得怀疑的.
使用扫描仪意味着这个问题和答案提到的所有其他事情.扫描仪不仅仅是关于如何解决扫描仪的这些常见问题,这些问题在扫描仪错误的几乎所有问题中始终存在共病问题.它永远不会只是大约next() vs nextLine(),这只是该类实现的挑剔的一个症状,代码发布中总会有其他问题询问有关Scanner的问题.
答案显示了99%的使用Scanner并在StackOverflow上询问的情况的完整,惯用的实现.
特别是在初学者代码中.如果您认为这个答案过于复杂,那么请向讲师告诉新学生使用Scanner,然后再解释复杂性,怪癖,非明显副作用及其行为的特殊性.
关于Principle of least astonishment的重要性以及为什么一致的行为和语义在命名方法和方法参数中很重要,扫描仪是一个很好的教学时刻.
给学生注意:
You will probably never actually see Scanner used in
professional/commercial line of business apps because everything it
does is done better by something else. Real world software has to be
more resilient and maintainable than Scanner allows you to write
code. Real world software uses standardized file format parsers and
documented file formats, not the adhoc input formats that you are
given in stand alone assignments.