scanner错误关闭导致的异常

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 found

原因

下面是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()会报错。

是否可以通过重新开启System.in的方式补救呢?

遗憾的是,至少作为java的使用者来说是不可以的,除非我们能控制jvm运行。

这涉及到System.in是如何开启的,简单来说因为System.in是特殊的系统资源,由jvm负责开启,无法通过java代码重新初始化System.in。

如果查看System.in的代码我们就能发现它通过native方法实现初始化,在native方法中将控制台或文件句柄传输给System.in来完成。

同样的,Systerm.out System.err也是无法重新被开启的资源,对于它们,close方法应该被谨慎的调用。

(ps:实际上有什么原因关闭呢?)

让我们把问题拓展开来

实际上,所有的能够以System.in/out/err为构造器参数的包装器类的close方法都应该被考虑,

可以看到jdk的设计者并没有区别对待普通的流和System.in/out/err,

而包装器类的close方法关闭底层流对于普通流来说是很合理的,因此我们可以推测事实上其他的包装器的close方法也可能导致关闭System.in/out/err。

常用的bufferinputstream就是如此。

jdk7引入的带资源的try语法糖产生隐蔽的问题

jdk7引入的带资源的try语法糖隐式的帮助程序员调用close方法,

遗憾的是该方法也会产生上述问题,甚至更难被发现。

我们有必要积极的关闭不再需要的流嘛?如何对待io.close?如何预防该问题?

从性能的角度来说,积极关闭流是必须的,实际上如果我们使用findbugs等代码规范工具,能发现关闭io是被强烈推荐的。

如果你使用idea的话,建议在close之前,使用快捷键ctrl+b进入close方法的源代码来查看其关闭机制。这种方法非常简便,当然eclipse应该也有插件可以实现类似功能。

我们也可以通过包装System.in/out/err来安全的使用它们,实际上利用装饰器模式,覆盖System.in/out/err的close方法即可。

对scanner.close方法的误解以及无法补救的错误的更多相关文章

  1. eclipse 从git取项目,导入为maven项目,新加的方法,报加载主类错误

    eclipse 从git取项目,导入为maven项目,新加的方法,报加载主类错误 具体描述: 整体编译能够编译成功,但新加一个java,里面创建一个main方法,运行时,报无法加载主类的错误, 整体编 ...

  2. Java Scanner nextLine方法跳过

    问题描述 Scanner使用了nextInt方法的时候,如果接下来要使用nextLine,会获取不到内容 原因 因为Scanner读取用户输入数据,是先判断缓冲区是否含有数据,没有则接收用户输入的数据 ...

  3. 对 jQuery 中 data 方法的误解

    一直以来都认为新版本中 data 是调用 dataset 实现的,对于低版本IE则采用 getAttribute其实一直是我误解了,也不知道最初这个想法是怎么来的.难道我被盗梦了? 今天 谢亮 兄弟和 ...

  4. Scanner使用方法

    import java.util.Scanner; //导入包 public void main (String args[]){ Scanner a=new Scanner(System.in); ...

  5. Scanner输入方法

    输入语句: * import java.util.Scanner; * System.out.println("请输入你想输入的东西:"); * Scanner (自定义)sc = ...

  6. 关于java和JS中的lastIndexOf方法的误解。

    今天看JS的数组的lastIndexOf()方法,看书上的例子,怎么看都觉得不对劲.后来详细读了几遍解释,用java也测试了下,才发现,之前的理解完全是错误的. 上例子: String nums=&q ...

  7. angularjs 初始化方法执行两次以及url定义错误导致传值错误问题

    1.初始化方法执行两次以上的问题定义一个 route.如下所示:.state('main.channelQryDetail', { url:'/channelDetail/:channelNo/:pa ...

  8. eclipse使用struts2找不到action方法或找不到action的错误记录

    在确认web.xml已经配置, 配置好struts.xml , 代码没有报错, jar包没有问题, 服务器也没有问题, 代码逻辑没有问题, 关键字方法名action都没有写错, 可以运行旧的相同的代码 ...

  9. centos ftp服务器搭建 vsftpd 匿名访问配置方法 ftp 550 Failed to open file 错误处理

    vsftpd是linux下常用的ftp服务软件,配置起来其实不复杂,只是网上很多文章,配置后都无法成功.我使用它是用于局域网内部分享文件的,所以使用匿名的方式. ftp本身密码是明文传输的,如果需要安 ...

随机推荐

  1. 前端PS常用切图技巧

    前言:前端涉及到的 ps 操作不算复杂,基本上就是切图,本文总结了常用的几种切图技巧. 工具:photoshop cs6 . photoshop cc 1. 传统切图 01 这是最笨的一种方法,核心就 ...

  2. Delphi Android 将Google ZXing 整合(调用Jar文件)

    前篇文章介绍了在delphi App(以下简称App)中可使用intent来调用Google ZXing 条码扫描器(以下简称zx),其各有优缺点,优点是我们不需关注zx本身的细节,只需调用其接口即可 ...

  3. Win8 Metro(C#)数字图像处理--2.75灰度图像的形态学算法

    原文:Win8 Metro(C#)数字图像处理--2.75灰度图像的形态学算法 前面章节中介绍了二值图像的形态学算法,这里讲一下灰度图的形态学算法,主要是公式,代码略. 1,膨胀算法 2,腐蚀算法 3 ...

  4. SQLServer 可更新订阅数据冲突的一个原因

    原文:SQLServer 可更新订阅数据冲突的一个原因 可更新订阅为什么有冲突? 可更新订阅中,当升级增加一个字段时,通常在发布服务器的发布数据库中增加,对表增加字段后,发布自动同步到订阅数据库中(复 ...

  5. 零元学Expression Blend 4 - Chapter 6 如何置入Photoshop档案以及入门动画设计

    原文:零元学Expression Blend 4 - Chapter 6 如何置入Photoshop档案以及入门动画设计 本章将教大家如何把Photoshop档案置入Expression Blend ...

  6. 利用docker在window7下安装TensorFlow

    安装过程下碰了不少坑,记录一下安装过程,方便以后有需要时复用. 1.安装docker 下载最新版本的docker并且默认安装即可,安装后打开Docker Quickstart Terminal,初次进 ...

  7. 12 寸 Retina MacBook 的大秘密: 可用移动电源充电

    苹果新款12寸Retina MacBook虽然只有一个USB-C接口,但这个接口的能力却十分强大.它不仅可以进行数据传输和视频输出,还能接收和输入电源.这也就是说,你可以使用移动电源对其进行充电,如果 ...

  8. xe5 firemonkey关闭应用程序

    在FMX中,由Activity替代了Form的概念,虽然TForm类仍然存在,但MainForm通过关闭函数无法结束程序,使用Application.Terminate均无效,调整为: uses   ...

  9. Qt使用MinGW编译,如何忽略警告

    Qt编译时经常出现以下警告: warning: unused parameter 'arg1' [-Wunused-parameter] warning: unused variable 'i' [- ...

  10. SQLite实现内存键值存储

    SQLite数据文件往Linux内存文件系统/dev/shm/data.sqlite3一放,就是内存级读写性能的SQL系统.用SQLite实现内存键值存储:CREATE TABLE IF NOT EX ...