如果您查看像 hasNext(String) 或 hasNextDouble 这样的扫描仪方法的文档,您会发现它
投掷:
IllegalStateException - 如果此 扫描仪 已关闭
(强调我的)
所以要抛出IllegalStateException,你首先需要关闭扫描器,而不是它正在读取数据的流。
让我们看一下这个例子:
Scanner sc = new Scanner(System.in);
System.out.println("type something:");
System.out.println(sc.hasNext());// true
System.out.println("your data: "+ sc.nextLine());
sc.close();
System.out.println("type something:");
System.out.println(sc.hasNext());// throws java.lang.IllegalStateException: Scanner closed
最后一行抛出IllegalStateException,因为您在关闭的扫描仪上调用hasNext方法(所以我们知道在调用它读取的sc.close()流之后也必须关闭,所以我们可以安全地假设没有更多元素读取,或者由于流已关闭,我们可能无法读取它)。
现在,如果我们不关闭扫描仪而是关闭System.in,我们仍然可以使用此扫描仪实例而不会出现异常。所以让我们简单地将sc.close(); 更改为System.in.close()(为简单起见,我将跳过异常处理):
Scanner sc = new Scanner(System.in);
System.out.println("type something:");
System.out.println(sc.hasNext());// true
System.out.println("your data: "+ sc.nextLine());
System.in.close();
System.out.println("type something:");
System.out.println(sc.hasNext());// false
如您所见,这里没有例外,因为关闭的不是扫描仪,而是正在读取哪个扫描仪的流。
为什么关闭System.in 不会导致扫描器抛出异常?
我怀疑这里不抛出异常的决定是假设异常象征代码问题。如果程序员允许关闭扫描仪,他还应该确保不会在任何地方使用这个特定的关闭扫描仪实例。
现在返回 false 而不是抛出异常是正常反应,因为没有更多元素要读取。因此,如果扫描仪正在读取的流自然关闭(例如,当我们读取文本文件并读取其最后一行,因此没有更多内容可读取)扫描仪会像正常情况一样处理这种情况(因此无需指出这是一些 特殊情况)。
现在在您的循环中,您可以将这两种情况结合起来。您的代码可以简化为:
Scanner sc = new Scanner(System.in);
System.out.println("type something:");
System.out.println(sc.hasNext());// true
System.out.println("your data: "+ sc.nextLine());
System.in.close();
sc = new Scanner(System.in);//IMPORTANT
System.out.println("type something:");
System.out.println(sc.hasNext());// false
如你所见
sc = new Scanner(System.in);//IMPORTANT
您正在创建尚未关闭的扫描仪新实例,因此其 hasXYZ 方法始终返回 false,因为 System.in 无法提供更多值。
额外的陷阱
我之前没有提到的一个问题是,如果输入错误,这既不是"exit",也不是double,如果你没有使用任何nextXZY从扫描器中消耗无效的缓存值hasNext("exit") 或 hasNextDouble 之类的方法仍将基于该无效数据,例如:
Scanner sc = new Scanner("foo 1");
System.out.println(sc.hasNextInt());//false because `foo` is not integer
System.out.println(sc.hasNextInt());//also false because we are still
//reading `foo` which is not integer
String str = sc.next();//lets read (sonsume) foo
System.out.println(sc.hasNextInt());//true since 1 is integer
解决方案
此类问题的最简单解决方案是仅创建一个 Scanner 实例,该实例将处理 System.in 并在整个应用程序中重用它。然后在您的应用程序结束时,您可以决定关闭您的扫描仪或System.in。
所以你的代码看起来像:
boolean finished;
Scanner inputScanner = new Scanner(System.in);
do {
finished = inputScanner.hasNext("exit");
boolean validNumber = inputScanner.hasNextDouble();
if (validNumber) {
double number = inputScanner.nextDouble();
System.out.print(number);
} else if (!finished) {
System.out.println("Please try again.");
inputScanner.next();// lets not forget to consume from scanner cached
// invalid data which is neither double or "exit"
}
} while (!finished);
inputScanner.close();