引言:想对比用于控制台输入的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 stubScanner 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 closedprivate Readable source; // The input sourcepublic 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
为了避免报错,只好在最后再关闭了