最近实验过程中遇到了NoSuchElementException异常,查询各种资料并经过实践发现是由于提前关闭Scanner引起的异常。
考虑如下代码:
import java.util.Scanner;
public class TestScanner {
public static void test() {
Scanner b = new Scanner(System.in);
System.out.println("test:");
int number = b.nextInt();
System.out.println("test: " + number);
b.close();
}
public static void main(String[] args) {
Scanner a = new Scanner(System.in);
test();
System.out.println("main:");
int number = a.nextInt();
System.out.println("main: " + number);
a.close();
}
}
main函数中调用test函数,让用户输入两个int型数据,然后打印出来。
但是运行后却发现在输入第一个数但还未输入第二个数时就抛出了NoSuchElementException
异常。
JDK文档中对于此异常的描述如下:
Thrown by various accessor methods to indicate that the element being requested does not exist.
翻译成通俗的语言就是指在访问不存在的元素时会抛出此异常,结合上面的简单程序,我们很容易想到可能是Scanner对象不存在引起的异常(其他部分十分简单,可能性不大)。
那么为什么会造成此异常呢?难道是main中的Scanner对象a和test中的Scanner对象b相互影响?
实际上问题出在System.in上。
查询JDK文档后可发现,Scanner类的构造方法接收一个InputStream对象:public Scanner(InputStream source);
而System.in是定义在System类中的一个InputStream类型的常量(public static final InputStream in
),static意味着“只有一个”,所以任何通过new Scanner(System.in)
构造出的Scanner对象都和同一个InputStream对象System.in相关联。
因此关闭任何一个Scanner对象,其他Scanner对象也关闭了。表现在上述事例代码中即是:test函数中关闭了Scanner对象b,使得main函数中的Scanner对象a也关闭了,再次访问a进行输入就抛出了NoSuchElementException
异常。
解决方法也很简单——在test函数中不关闭Scanner对象,只在main函数结尾关闭。
import java.util.Scanner;
public class TestScanner {
public static void test() {
Scanner b = new Scanner(System.in);
System.out.println("(test)输入第一个数");
int number = b.nextInt();
System.out.println("test: " + number);
// b.close();
}
public static void main(String[] args) {
Scanner a = new Scanner(System.in);
test();
System.out.println("(main)输入第二个数");
int number = a.nextInt();
System.out.println("main: " + number);
a.close();
}
}
运行成功:
总结
只在程序结尾对Scanner对象进行一次关闭!!!