引言:想对比用于控制台输入的Scanner和BufferedReader,因此放在同一个方法中,之前学习或者使用时没有特别注意过要不要在使用完后关闭Scanner,最初根据Eclipse的提示,在使用完Scanner后调用了close(),可是当我再次运行的时候,直接影响到后面InputStreamReader,然后分析原因:从第19行开始,后面的代码都没有用到Scanner,理论上没问题的,然后再看了看,Scanner中有用到System.in,InputStreamReader中也有用到System.in,出问题应该就在System.in了。
package com.temp;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;
public class Test {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
System.out.println("please input a Integer number");
int number = scanner.nextInt();
System.out.println("your input is " + number);
// scanner.close();
InputStreamReader inputstreamreader = new InputStreamReader(System.in);
BufferedReader bufferReader = new BufferedReader(inputstreamreader);
System.out.println("please input your info");
String string = bufferReader.readLine();
System.out.println("your information is " + string);
}
}
在我们写代码的时候,如果申明后用完Scanner后没有及时关闭,IDE会自动提示我们需要关闭流
(Eclipse IDE会有提示,Intellij IDEA没有提示)
如果我们没有手动关闭,虽然Scanner对象最终会进入被回收的队列中,但不是立刻回收,这会造成内存占据。
为了节省内存我们一般在使用完Scanner后会调用scanner.close();来关闭输入流。
下面开始分析:
1、查看close()方法的源码
/**
* Closes this scanner.
*
* If this scanner has not yet been closed then if its underlying
* {@linkplain java.lang.Readable readable} also implements the {@link
* java.io.Closeable} interface then the readable's close method
* will be invoked. If this scanner is already closed then invoking this
* method will have no effect.
*
*
Attempting to perform search operations after a scanner has
* been closed will result in an {@link IllegalStateException}.
*
*/
private boolean closed = false; // Boolean indicating if this scanner has been closed
private Readable source; // The input 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;
}
在这源码中我们可以看到source就是输入的source,对于Scanner输入的source就是System.in,close()方法中有判断
if (source instanceof Closeable)
instanceof 关键字用法:instanceof 是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。
因此如果source是Closeable的一个实例,那么source也会被关闭。
2、查看System源码(第77行开始)
/**
* The "standard" input stream. This stream is already
* open and ready to supply input data. Typically this stream
* corresponds to keyboard input or another input source specified by
* the host environment or user.
*/
public final static InputStream in = null;
注释部分翻译:
“标准”输入流。该流已经打开并准备提供输入数据。通常,此流对应于键盘输入或由主机环境或用户指定的另一个输入源。
----我们还注意到InputStream是被final修饰的----
3、查看InputStream源码
我们发现InputStream实现了Closeable接口
(也可直接查看JDK官方文档)
综上,由于InputStream实现了Closeable接口,因此InputStream会被关闭,但是同时InputStream是被final修饰过的,只能被实例化一次,因此我们后面代码再使用System.in也依然是被关闭的。
因此在后面使用的时候会报错:Stream closed
为了避免报错,只好在最后再关闭了