调用scanner.close()报错Java.io.Exception: Stream closed; 的原因分析

引言:想对比用于控制台输入的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.
     *
     * <p> 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 <tt>close</tt> method
     * will be invoked.  If this scanner is already closed then invoking this
     * method will have no effect.
     *
     * <p>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也会被关闭。

扫描二维码关注公众号,回复: 11615816 查看本文章

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

为了避免报错,只好在最后再关闭了

猜你喜欢

转载自blog.csdn.net/c_lanxiaofang/article/details/108425467