才发现Scanner也是一种资源,在更新大作业代码时发现的Scanner可以被关闭之后,就仿佛看见一个新大陆。
出于减少资源浪费的目的,我决定对每一个创建的Scanner对象在使用后立马close掉。毕竟我实在是用了太多的Scanner对象,下面的类我不知道调用了多少次。
public class InputInteger {
private int number;
public boolean inPutInteger(){
Scanner in=new Scanner(System.in);
try{
//System.out.println("请输入一个整数");
this.number=in.nextInt();
if(this.number<0){
throw new inputException("不能输入小于0的整数!");
}else{
return true;
}
}catch (Exception e){
e.printStackTrace();
System.out.println("请输入不小于0的整数,更不要输入字符串!");
return false;
}
finally {
in.close();//尝试:每次输入结束后,关闭Scanner对象,减少资源的额外使用
}
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
这个代码是我专门为输入合法整数而写的一个专类,它里面用到了我自己定义的异常类inputException.
由于我给定的输入是整数,所以我怕室友这个暴力测试员偷偷输入字符串而导致程序崩溃,因而在抛出异常后对整个输入进行try——catch处理。
在输入完成后我在finally中加了close的调用,然后,测试时就,就出bug了
像这样运行出了无限死循环……
于是乎,我开始找资料。
发现,Scanner中的close不仅关闭了Scanner还关闭了System.in,(System.in是有final修饰的静态属性,它是InputStream对象,下面是源码:
public final static InputStream in = null;
,它只能被实例化一次,所以所有Scanner对象共用同一个System.in对象)也就意味着再也无法使用这个资源了,所以一定要谨慎的使用Scanner的close方法,要确保你不需要再输入了才可以关闭,否则下次就不能再使用了。
我觉得可以这样说:
Scanner是外层流,而System.in是内层流,你一旦关闭了外层流,那么与之共存的内存流也会随之关闭,再加上System.in被final修饰,导致只能被实例化一次,故关闭一次就关闭相当于"关闭了所有Scanner对象"
这就是关闭一次Scanner对象后无法再次使用的原因,哪怕你建了一个新的Scanner对象依旧于事无补,并且Scanner中的close方法会在程序结束是隐式调用,就算你不用他也会自己关。