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. C# 自定义泛型类,并添加约束

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...

  2. WPF数据验证方式

    WPF有两种数据验证的方式: 1 在数据对象上进行验证:普通属性验证或者实现IDataErrorInfo接口 2 可以再绑定规则上进行验证:ExceptionValidationRule异常验证规则 ...

  3. C# GetFiles

    var path = AppDomain.CurrentDomain.BaseDirectory + "Images\\Rooms\\"; // string[] patterns ...

  4. CPU和GPU双低效,摩尔定律之后一万倍 ——写于TPU版AlphaGo重出江湖之际

    本文来自计算机体系结构专家王逵.他认为,“摩尔定律结束之后,性能提升一万倍”不会是科幻,而是发生在我们眼前的事实.   2008年,<三体2:黑暗森林>里写到:   真的很难,你冬眠后不久 ...

  5. Hadoop分布式文件系统

    在一个经典的数据架构中,Hadoop是处理复杂数据流的核心.数据从各种系统中收集而来,并汇总导入到Hadoop分布式文件系统HDFS中,然后通过MapReduce或者其它基于MapReduce封装的语 ...

  6. Qt在Windows下如何创建无CMD窗口控制台程序

    默认情况下,用Qt新建一个控制台程序,运行时会弹出CMD窗口.如何把窗口去掉呢? *.pro文件默认是这样的: TEMPLATE = app CONFIG += console CONFIG -= a ...

  7. 任何一件事,如果你不投入时间和精力去驯养,就不可能产生真正的兴趣和热爱(Focus Feedback FixIt的原理) good

    这两本书和我们说的兴趣结合起来,为我们指明了精进的道路: 选择一个你感兴趣的方向 刻意练习 持续投入时间和精力 所谓刻意练习,简单说就是“3F”,即: Focus Feedback Fix it Fo ...

  8. Netty源码分析--Reactor模型(二)

    这一节和我一起开始正式的去研究Netty源码.在研究之前,我想先介绍一下Reactor模型. 我先分享两篇文献,大家可以自行下载学习.  链接:https://pan.baidu.com/s/1Uty ...

  9. pip与conda的区别

    pip和conda到底有什么不一样? 今天看到我的foreman开始报错去询问才发现.我们的python包管理工具已经从pip整体迁移到了conda..最近的迁移真的非常多..前端也在迁移打包 跟着发 ...

  10. Java学习笔记——Socket实现文件传输

    我越是逃离,却越是靠近你. 我越是背过脸,却越是看见你. 我从你开始, 我在你结束. 需求:实现局域网下socket传输文件. 客户端步骤: 1.建立与服务器的连接 2.创建client输出流 3.创 ...