对scanner.close方法的误解以及无法补救的错误
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方法的误解以及无法补救的错误的更多相关文章
- eclipse 从git取项目,导入为maven项目,新加的方法,报加载主类错误
eclipse 从git取项目,导入为maven项目,新加的方法,报加载主类错误 具体描述: 整体编译能够编译成功,但新加一个java,里面创建一个main方法,运行时,报无法加载主类的错误, 整体编 ...
- Java Scanner nextLine方法跳过
问题描述 Scanner使用了nextInt方法的时候,如果接下来要使用nextLine,会获取不到内容 原因 因为Scanner读取用户输入数据,是先判断缓冲区是否含有数据,没有则接收用户输入的数据 ...
- 对 jQuery 中 data 方法的误解
一直以来都认为新版本中 data 是调用 dataset 实现的,对于低版本IE则采用 getAttribute其实一直是我误解了,也不知道最初这个想法是怎么来的.难道我被盗梦了? 今天 谢亮 兄弟和 ...
- Scanner使用方法
import java.util.Scanner; //导入包 public void main (String args[]){ Scanner a=new Scanner(System.in); ...
- Scanner输入方法
输入语句: * import java.util.Scanner; * System.out.println("请输入你想输入的东西:"); * Scanner (自定义)sc = ...
- 关于java和JS中的lastIndexOf方法的误解。
今天看JS的数组的lastIndexOf()方法,看书上的例子,怎么看都觉得不对劲.后来详细读了几遍解释,用java也测试了下,才发现,之前的理解完全是错误的. 上例子: String nums=&q ...
- angularjs 初始化方法执行两次以及url定义错误导致传值错误问题
1.初始化方法执行两次以上的问题定义一个 route.如下所示:.state('main.channelQryDetail', { url:'/channelDetail/:channelNo/:pa ...
- eclipse使用struts2找不到action方法或找不到action的错误记录
在确认web.xml已经配置, 配置好struts.xml , 代码没有报错, jar包没有问题, 服务器也没有问题, 代码逻辑没有问题, 关键字方法名action都没有写错, 可以运行旧的相同的代码 ...
- centos ftp服务器搭建 vsftpd 匿名访问配置方法 ftp 550 Failed to open file 错误处理
vsftpd是linux下常用的ftp服务软件,配置起来其实不复杂,只是网上很多文章,配置后都无法成功.我使用它是用于局域网内部分享文件的,所以使用匿名的方式. ftp本身密码是明文传输的,如果需要安 ...
随机推荐
- Android零基础入门第37节:初识ListView
原文:Android零基础入门第37节:初识ListView 之前我们学习的一些UI组件都比较简单,但是在实际开发中,会经常遇见列表界面设计,如通讯录.电话列表.信息列表等.那么从本节开始来详细学习列 ...
- LINQ学习笔记(一)
LINQ,语言集成查询(Language Integrated Query)是一组用于C#和Visual Basic语言的扩展. 它允许编写C#或Visual Basic代码以查询数据库相同的方法操作 ...
- windows和linux双系统,重新分区后修复grub
我电脑里装的是 windows 7 profressional 和 fedora 12 ,本来给 C 盘分了 50G ,原本以为够了,结果50G 瞬间用完,于是乎开始重新分区. PQ 是不能用了,上网 ...
- Qt编程中QDiaog的ESC建
最近使用QDialog时,按了下Esc键,导致QDialog被关闭,而后续的数据处理出现了问题.原来在QDialog中按下Esc键会默认调用reject()方法而不是closeEvent(QClose ...
- Delphi子类调用祖父类的虚函数
因为看Delphi书的时候,就产生了疑惑.老讲调用父类虚函数,但是万一需要调用祖父虚函数怎么办?后来又经常在C++里看到,就更疑惑了 type TA = class procedure ShowMsg ...
- 基于SAP HANA平台的多团队产品研发
工欲善其事必先利其器.要提高多团队的开发效率,而且还是在SAP HANA平台上,建议大家还是本着“慢就是快”的原则,不要急功近利,在没有准备好团队开发的架构时就匆忙开始功能的开发.匆忙功能开发就算了, ...
- Qt+VS编译器:默认库“library”与其他库的使用冲突;使用 /NODEFAULTLIB:library(我曾经碰到过,修改qmake.conf,但我修改的是VS的IDE配置)good
找到qt安装目录下的mkspecs文件夹,在里面找到你使用的对应版本编译器,打开qmake.conf.稍等: /MD:动态链接多线程库(msvcrt.lib).使用该选项时,需要用/NODEFAULT ...
- centos yum 安装 jdk1.8
JDK: 版本:1.8 服务器默认安装1.7,所以不使用默认安装 yum -y list java* --查看yum的jdk安装包 yum install java-1.8.0-openjdk jav ...
- [Err] 1146 - Table 'performance_schema.session_status' doesn't exist已解决
刚刚接触MySQL,就往数据库添加数据,就遇到这个问题 解决方案就是找到你安装MySQL的bin目录 然后在cmd输入 mysql_upgrade -u root -p --force 回车,然后输入 ...
- SYN591型 多功能数字面板表
SYN591型 多功能数字面板表 多功能数字面板表数字面板表使用说明视频链接: http://www.syn029.com/h-pd-248-0_310_44_-1.html 请将此链接复制到浏 ...