java.util.NoSuchElementException


問題引入

Java商店作業不同函數里需要獲取用戶輸入,用Scanner的時候,出現了異常java.util.NoSuchElementException

作業中代碼模式如下,func1func2中都使用Scanner並關閉它。然后在main中依次調用func1func2func2產生異常。說func1func2其實不合適,應該加個括號.....…..懶得加了

//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)


*/

異常產生原因

func1sc.close();語句關閉了Scannerfunc2中使用Scanner產生異常

因為System.inSystem類的靜態成員,所以不同Scanner對象內的in是同一個in`

func1func2中都用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的構造方法,和Scannernext(),能力有限,點到為止

作者:@臭咸魚

本文為作者原創,轉載請注明出處:https://chouxianyu.github.io/2018/11/03/java.util.NoSuchElementException/#more

歡迎轉發和評論


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2024 CODEPRJ.COM