本地字符串扫描器何时收集垃圾?

When does a local String Scanner get garbage collected?

假设我有一个 String s 并且我想通过 Builder 中的此方法使用 Scanner 遍历它:

private void scan(String s){    
    Scanner scanner = new Scanner(s);
    while (scanner.hasNext()){
        //do something
    }
}

假设 s 是一个变量,是另一个 Object 的一部分。

public class Person{
    String name;
    //rest of code
}

现在假设这个对象存储在一个单例中,该单例存储数据以便在程序的生命周期内随时可用

public class Singleton{
    private List<Person> list = new ArrayList<>();
    //rest of code
}

我的问题是:一旦 scan(String s) 完成 运行,scanner 会发生什么?它会继续存在还是会在达到其范围后被收集,从而释放资源?如果它没有被收集,如果我将 scan(String s) 更改为:

会发生什么
private void scan(String s){    
    Scanner scanner = new Scanner(s);
    while (scanner.hasNext()){
        //do something
    }
    scanner.close();
}

还是应该首选后一种形式?

始终首选关闭文件上的扫描程序,以便确定性地清理文件资源。

在 Scanner 被丢弃后可以清理字符串,假设它没有在其他任何地方被引用。

对于扫描器,我建议使用 try-with-resource

try (Scanner scanner = new Scanner(filename)) {
    while (scanner.hasNext()){
        //do something
    }
}

String 上的 Scanner 的情况下,Scanner 将有一个 StringReader 作为其来源,它会引用字符串,但不会引用扫描仪本身。由于 StringReader 完全在内存中,因此不需要关闭或清理。关闭它没有什么坏处,但是,如果您确实选择关闭它,则应该将关闭调用放在 finally 块中,或者通过使用 try-with-resources:[=20 使其隐式调用=]

Scanner scanner = new Scanner(s);
try {
    while (scanner.hasNext()) {
        // do something
    }
} finally {
    scanner.close();
}

或:

try (Scanner scanner = new Scanner(s)) {
    while (scanner.hasNext()) {
        // do something
    }
} // close will be implicitly called

规则是,您应该始终关闭您打开的任何内容以确保资源得到清理。

对于文件上的扫描程序,关闭它很重要。

对于 System.in 上的扫描程序,您没有 打开 System.in,因此您没有责任 [=34] =]关闭它。

对于字符串上的扫描器,或者从 ByteArrayInputStreamStringReader 读取时,没有任何有意义的资源需要关闭,但它可能最好以一种会调用 close 的方式编写内容,以防万一您稍后将其切换为从文件中读取(或只是为了养成习惯)。

对于你关于垃圾收集的问题,你永远不能说什么时候会被垃圾收集。如果您的程序永远不会 运行 内存不足,垃圾收集器甚至可能不会 运行。但是,由于 String 和 StringReader 都没有维护对 Scanner 的引用,因此当方法 scan(String) returns.