如果在代码中关闭了Scanner,也就是调用了Scanner.close()这个方法,那么在接下来的代码中将无法再使用Scanner,即便再次声明了一个新的Scanner对象也是如此。

Scanner sc = new Scanner(System.in);//创建第一个Scanner对象
sc.close()//将其关闭
//int i = sc.nextInt();    对于该行代码无法使用应该没有争议,因为sc已经被关闭了
sc = new Scanner(System.in);//重新创建一个Scanner对象赋值给sc
//也可以选择重新建立一个变量
int i = sc.nextInt();

以上代码运行后会抛出异常java.util.NoSuchElementException;

这个异常的具体来源及原因可以从以下文章中了解,在此不重复赘述。


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:scanner.close()的需要注意
 


但本文的撰写目的是为了解答应该在什么时候调用Scanner的close()方法,而非单纯的解析抛出异常的原因。

首先Scanner的close()方法会关闭System.in,也就是Scanner对象在被初始化时所传入的参数。

System.in是一个final常量,所以在整个方法中只会被实例化一次。

这也就导致了在第二次创建Scanner对象的时候并没有一个全新的System.in被传入,而是一个已经被关闭了的System.in。

那么是否能够重新打开System.in呢?

就目前查到的资料中表示System.in在被关闭后并不能重新打开,对于具体原因还不清楚。

所以如果要关闭Scanner的话一定要确保在同一方法下接下来不会再调用Scanner来接受输入。

接下来是为什么要关闭Scanner。

我们之所以要关闭Scanner是因为System.in在被第一次声明时会打开InputStream,而输入流是非常占据内存的,为此我们通常为了节省内存考虑会选择调用Scanner.close()来关闭输入流,从而节省内存。

如果一个方法中创建了Scanner对象,却没有关闭,那么在方法结束后,Scanner对象虽然会进入被回收的队列中,但不是立刻回收。而这会给计算机带来一定的负担,为了避免造成大量的内存占据,至少在方法结束前应该调用Scanner的close()方法。

例如:

public int run(){
    Scanner sc = new Scanner(System.in);//创建Scanner对象
    int i = sc.nextInt();
    //代码块(其中再次调用了sc)
    sc.close()//关闭Scanner,也就是关闭输入流
    //如果不写sc.close()的话尽管sc同样会在一段时间后被回收,但如果run函数被大量重复调用的话,就会导致一定程度的内存浪费
    return i;
}

需要注意的是,如果函数中有多个地方可能会结束方法,那么要在每次结束前确保Scanner对象被close了。

但如果能够保证接下来的部分不会在运用到Scanner,也可以提早进行Scanner的close()方法的调用。

这也就是为什么Scanner的close()不是总被放在最后的原因。

同时Scanner在方法中也占据了一定的内存,会影响到运行,能够及早释放也会更好。

例如:

public int run(){
    Scanner sc = new Scanner(System.in);//创建Scanner对象
    int i = sc.nextInt();
    sc.close()//关闭Scanner
    //代码块(其中没有调用sc)
    return i;
}

这样可以进一步节省内存,也保证了不用担心后面会出现突然结束方法而没有关闭Scanner的情况。

ps:虽然这样就要注意是否要再次调用Scanner了。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐