public class test2 { public static void main(String[] args) { Scanner scanner1 = new Scanner(System.in); System.out.println("run scanner1.close()"); scanner1.close(); Scanner scanner2 = new Scanner(System.in); System.out.println("run scanner2.nextLine()"); scanner2.nextLine(); } }
可是會在scanner2.nextLine()調用時拋出異常
java.util.NoSuchElementException: No line foundjava
下面是scanner的源碼程序員
// The input source private Readable source; 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; }
因此調用close方法並不單單關閉scanner類,同時關閉了初始化時做爲參數傳入的Readable對象。
在示例代碼中scanner1.close();關閉了System.in,因此雖然初始化scanner2沒有問題,可是readLine()會報錯。安全
遺憾的是,至少做爲java的使用者來講是不能夠的,除非咱們能控制jvm運行。
這涉及到System.in是如何開啓的,簡單來講由於System.in是特殊的系統資源,由jvm負責開啓,沒法經過java代碼從新初始化System.in。
若是查看System.in的代碼咱們就能發現它經過native方法實現初始化,在native方法中將控制檯或文件句柄傳輸給System.in來完成。
一樣的,Systerm.out System.err也是沒法從新被開啓的資源,對於它們,close方法應該被謹慎的調用。
(ps:實際上有什麼緣由關閉呢?)eclipse
實際上,全部的可以以System.in/out/err爲構造器參數的包裝器類的close方法都應該被考慮,
能夠看到jdk的設計者並無區別對待普通的流和System.in/out/err,
而包裝器類的close方法關閉底層流對於普通流來講是很合理的,所以咱們能夠推測事實上其餘的包裝器的close方法也可能致使關閉System.in/out/err。
經常使用的bufferinputstream就是如此。jvm
jdk7引入的帶資源的try語法糖隱式的幫助程序員調用close方法,
遺憾的是該方法也會產生上述問題,甚至更難被發現。ide
從性能的角度來講,積極關閉流是必須的,實際上若是咱們使用findbugs等代碼規範工具,能發現關閉io是被強烈推薦的。
若是你使用idea的話,建議在close以前,使用快捷鍵ctrl+b進入close方法的源代碼來查看其關閉機制。這種方法很是簡便,固然eclipse應該也有插件能夠實現相似功能。
咱們也能夠經過包裝System.in/out/err來安全的使用它們,實際上利用裝飾器模式,覆蓋System.in/out/err的close方法便可。工具