使用 scanner 過後,感覺應該像讀取檔案之後一樣将它關閉,是以調用 close() 方法。在下一次需要輸入時,再重新建立 scanner 對象讀取輸入。好像沒什麼問題。
然而運作時抛出異常如下。難道同一程式中 scanner 隻能建立一次嗎?
結合源碼分析,真正的原因在 <code>system.in</code>。我們來看 <code>system.in</code> 在 scanner 對象中的走向。
首先,從 <code>system</code> 類源碼中可以知道 <code>system.in</code> 是不可變的靜态資源,即隻有一份。從源碼說明中可以知道,它作為 <code>inputstream</code> 會在使用前被系統自動打開并連接配接到輸入源(如鍵盤),那也就是說它隻能被使用一次,如果被關閉就無法再使用了。
然後再看,在通過 <code>new scanner(system.in)</code> 建立 scanner 對象時,scanner 的一個構造器被調用,
這個構造器調用了另一個構造器,并傳入了 <code>system.in</code> 作為 <code>source</code> 參數。在這一個構造器中,scanner 對象的成員變量 <code>source</code> 被确定下來。
最後,當我們調用 <code>close()</code> 時,<code>source</code> 的 <code>close()</code> 方法會被調用,實際被關閉的就是 <code>system.in</code> 這一靜态資源。
是以當再一次建立 scanner 對象,傳入的是一個已經被關閉了的 <code>system.in</code>,它此時已經無法讀取輸入,是以在嘗試讀取操作時會抛出異常。
既然找到了原因:<code>input.close()</code> 使 <code>system.in</code> 過早地關閉了,那解決辦法自然有了:最後再調用 <code>close()</code>。可以有三種方式:
在需要時随時建立一個 scanner 對象傳入 <code>system.in</code>,但在使用後不馬上調用 <code>close()</code>,而是在所有擷取輸入操作結束後再調用 <code>close()</code>;
隻建立一個 scanner 對象,将其作為參數傳入需要擷取輸入的方法中,在所有擷取輸入操作結束後再調用 <code>close()</code>;
建立一個靜态 scanner 對象,當不再需要使用該靜态 scanner 對象擷取輸入後調用 <code>close()</code>。
第三種方式實作起來更加簡潔: