問題引入
Java商店作業不同函數里需要獲取用戶輸入,用Scanner
的時候,出現了異常java.util.NoSuchElementException
作業中代碼模式如下,func1
和func2
中都使用Scanner
並關閉它。然后在main中依次調用func1
和func2
,func2
產生異常。說func1
和func2
其實不合適,應該加個括號.....…..懶得加了
//Demo.java
import java.util.Scanner;
class Test{
void func1() {
Scanner sc=new Scanner(System.in);
//輸出用戶輸入,替代作業里的使用Scanner
System.out.print("Func1請輸入內容:");
System.out.println("Func1輸出"+sc.next());
//關閉Scanner
sc.close();
}
void func2() {
Scanner sc=new Scanner(System.in);
//輸出用戶輸入,替代作業里的使用Scanner
System.out.print("Func2請輸入內容:");
System.out.println("Func2輸出"+sc.nextInt());
//關閉Scanner
sc.close();
}
}
public class Demo{
public static void main(String[] args) {
Test t=new Test();
t.func1();
t.func2();
}
}
/*Console輸出如下:
Func1請輸入內容:小姐,請問你喜歡吃青椒嗎?
Func1輸出:小姐,請問你喜歡吃青椒嗎?
Func2請輸入內容:Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.Scanner.throwFor(Unknown Source)
at java.base/java.util.Scanner.next(Unknown Source)
at java.base/java.util.Scanner.nextInt(Unknown Source)
at java.base/java.util.Scanner.nextInt(Unknown Source)
at Test.func2(Demo.java:21)
at Demo.main(Demo.java:31)
*/
異常產生原因
func1
中sc.close();
語句關閉了Scanner
,func2
中使用Scanner
產生異常
因為System.in
是System
類的靜態成員,所以不同Scanner
對象內的in是同一個
in`
func1
和func2
中都用System.in
創建了Scanner
func1
打開Scanner
后將其關閉,這里間接地將System.in
也關閉了
func1
結束后運行func2
,這時再調用nextInt
,在System.in
已經關閉了的情況下,不能讀取到任何數據,就會產生 java.util.NoSuchElementException
解決方法
系統資源一旦釋放就不能再開啟了,所以只有確定不在使用系統的時候,才能將流關閉
所以應該在整個程序結束時釋放Scanner
等資源,而不是某個函數中每次使用Scanner
等資源后都釋放一次
問題引入中的代碼只是個模式,上邊的兩句話用在作業實際代碼里就好了
代碼分析
Scanner()
創建Scanner
對象代碼為Scanner sc=new Scanner(System.in);
構造函數源碼如下
public Scanner(InputStream source) {
this(new InputStreamReader(source), WHITESPACE_PATTERN);
}
可看出是調用了另外一個構造函數,繼續查看源碼
private Scanner(Readable source, Pattern pattern) {
assert source != null : "source should not be null";
assert pattern != null : "pattern should not be null";
this.source = source; //看這句
delimPattern = pattern;
buf = CharBuffer.allocate(BUFFER_SIZE);
buf.limit(0);
matcher = delimPattern.matcher(buf);
matcher.useTransparentBounds(true);
matcher.useAnchoringBounds(false);
useLocale(Locale.getDefault(Locale.Category.FORMAT));
}
至少知道了Scanner
內部還是用到了流,算是對流進行了封裝吧,使用起來更方便一些
close()
調用語句為sc.close();
,查看close()
源碼,如下
public void close() {
if (closed) //1.通過closed標志校驗Scanner是否已關閉;
return;
if (source instanceof Closeable) { //2.執行source的close()方法,
try { //將source關閉(這里為System.in);
((Closeable)source).close();
} catch (IOException ioe) {
lastException = ioe;
}
}
sourceClosed = true; //3.將sourceClosed標志設置為true,表示source已關閉;
source = null; //4.將source置為null,不再引用,處於可回收狀態;
closed = true; //5.將closed標志設置為true,表示Scanner已關閉;
}
可以知道關閉Scanner
的時候,((Closeable)source).close();
把System.in
關閉了
關閉后下次想再使用就當然有錯了~(除非構造函數里還再把in
給打開,但這樣也不太合理)
其實如果還可以再仔細看看Scanner
的構造方法,和Scanner
的next()
,能力有限,點到為止
作者:@臭咸魚
本文為作者原創,轉載請注明出處:https://chouxianyu.github.io/2018/11/03/java.util.NoSuchElementException/#more
歡迎轉發和評論