调用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();来关闭输入流。

调用scanner.close()报错Java.io.Exception: Stream closed; 的原因分析_第1张图片

下面开始分析:

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源码

调用scanner.close()报错Java.io.Exception: Stream closed; 的原因分析_第2张图片

我们发现InputStream实现了Closeable接口

(也可直接查看JDK官方文档)

调用scanner.close()报错Java.io.Exception: Stream closed; 的原因分析_第3张图片

综上,由于InputStream实现了Closeable接口,因此InputStream会被关闭,但是同时InputStream是被final修饰过的,只能被实例化一次,因此我们后面代码再使用System.in也依然是被关闭的。

因此在后面使用的时候会报错:Stream closed

调用scanner.close()报错Java.io.Exception: Stream closed; 的原因分析_第4张图片

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

调用scanner.close()报错Java.io.Exception: Stream closed; 的原因分析_第5张图片

你可能感兴趣的:(Java)