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方法便可。工具