Exception in thread "main" java.util.NoSuchElementException
public static void main(String[] args) {
add();
sub();
}
public static void add() {
Scanner scanner = new Scanner(System.in);
int number1 = scanner.nextInt();
int number2 = scanner.nextInt();
System.out.println(number1 + number2);
scanner.close();
}
public static void sub(){
Scanner scanner = new Scanner(System.in);
int number1 = scanner.nextInt();
int number2 = scanner.nextInt();
System.out.println(number1 - number2);
scanner.close();
}
자주 사용하는 Scanner 에대해 잘 알고 있다고 생각했다. 위의 코드를 작성하고 당연히 잘 실행될 줄 알았는데 에러가 발생했다.. 디버깅을 해보니 add() 실행 후 sub() 에서 int number1 = scanner.nextInt(); 행에서 에러가 발생했다. Scanner의 close() 실행 후에 System.in 도 같이 닫아버려서 생기는 문제인 것 같았다.
public void close() {
if (closed)
return;
if (source instanceof Closeable) {
try {
((Closeable)source).close();
} catch (IOException ioe) {
lastException = ioe;
}
}
sourceClosed = true;
source = null;
closed = true;
}
closed 와 source 의 값에 따라 결과 값이 달라진다. 그렇다면 closed 와 source 값이 무엇인지 Scanner 를 추적해보자.
public final class Scanner implements Iterator<String>, Closeable {
...생략
// The input source
private Readable source;
...생략
// Boolean indicating if this scanner has been closed
private boolean closed = false;
...생략
}
closed = false로 초기화된다.
source는 다른 곳에서 초기화되는 것 같다. Scanner의 생성자를 추적해보자.
public Scanner(InputStream source) {
this(new InputStreamReader(source), WHITESPACE_PATTERN);
}
private Scanner(Readable source, Pattern pattern) {
...생략
this.source = source;
...생략
}
public class InputStreamReader extends Reader
public abstract class Reader implements Readable, Closeable
public interface Readable
Scanner scanner = new Scanner(System.in); 로 인해 Readable source = new InputStreamReader(System.in); 로 초기화되고 scanner.close() 를 실행하게 되면 인자로 받은 System.in 을 close 하게 된다.
결과적으로 System.in.close() 를 실행하면 표준 입력 스트림이 닫히고, 이후에는 System.in 을 통해 사용자 입력을 받을 수 없게 된다.
공식문서에서는 아래와 같이 설명한다.