为什么我的inputScanner在第一次输入后没有阻塞?它进入连续循环。忽略此代码的其他细节。
public class Test {
public static void main(String[] args) {
boolean finished;
do {
Scanner inputScanner = new Scanner(System.in);
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.close();
} while (!finished);
}
}
编辑:在与此相关的上一篇文章中,提到“因此,如果您要稍后使用 System.in 请不要关闭它(如果它已关闭,我们无法重新打开它并从中读取任何数据,因此例外)”。为什么会这样?
为什么我的inputScanner在第一次输入后没有阻塞?
因为每次进入循环时都在创建一个新的扫描仪,所以第一次迭代中的对象与第二次及以后的迭代中的对象不同
public class Test {
public static void main(String[] args) {
boolean finished;
do {
Scanner inputScanner = new Scanner(System.in); //Here you're making a new instance of inputScanner each time you come to this line after the do-while loop ends.
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.close();
} while (!finished);
}
}
如果您希望它被“阻止”或“关闭”,请将此行移动到do{
行之前。
Scanner inputScanner = new Scanner(System.in);
对于第二个问题:
因此,如果您要使用 System.in 以后不要关闭它(如果它已关闭,我们无法重新打开它并从中读取任何数据,因此异常)
来自Oracle的文档:
"在扫描仪关闭后尝试执行搜索操作将导致IllegalStateException "
这就像试图让一个死人做某事,就像僵尸一样!(Java讨厌僵尸!D:
但是您不会得到那个< code > IllegalStateException ,因为正如我在回答您的第一个问题时所说的,每次进入< code>do-while循环时,您都在创建一个新的对象。
你为什么不能重新打开它?另请参阅Oracle的文档:
关闭扫描程序时,如果源实现了可关闭接口,它将关闭其输入源。
因此inputScanner.close关闭System.in.
并且由于OutputStream的关闭的一般契约(借助于这个回答):
public void off()抛出IOException
--
如果您查看扫描仪方法的文档,如hasNext(String)
或hasNextDouble
,您将看到
抛出:< br> IllegalStateException -如果此扫描仪关闭
(强调我的)
因此,要抛出 IllegalStateException
,您首先需要关闭 Scanner,而不是从中读取数据的流。
让我们来看看这个例子:
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
最后一行抛出<code>IllegalStateException</code>,因为您正在关闭的扫描程序上调用<code>hasNext</code〕方法(所以我们知道,在调用<code<sc.close()</code}之后,它从中读取的流也必须关闭,所以我们可以安全地假设没有更多的元素可以读取,或者由于流已关闭,我们可能不允许读取它)。
现在,如果我们不关闭扫描仪,而是关闭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
不会导致扫描程序引发异常?
我怀疑这里不抛出异常决定是基于这样的假设,即异常象征着代码有问题。如果程序员允许扫描器被关闭,他也应该确保扫描器的这个关闭的实例不会在任何地方被使用。< br >现在返回< code>false,而不是抛出exception,这是正常反应,因为没有更多元素要读取。因此,如果扫描器正在读取的流被自然关闭(就像我们读取文本文件并读取它的最后一行,所以没有更多要读取的内容),扫描器会像正常情况一样处理这种情况(所以没有必要指出这是某种异常情况)。
现在,在循环中,您可以将这两种情况结合起来。您的代码可以简化为:
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
无法提供更多值。
附加存水弯
我之前没有提到的一个问题是,在输入错误的情况下,如果您没有使用任何 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();