23

我使用 aStringReader将字符串转换为可以上传到 SFTP 服务器的内容(它需要一个流)。之后关闭它有什么意义StringReader吗?据我在源代码中看到的,它只是将字符串设置为null...

我可以这样做,但是由于 close 方法被标记为抛出 anIOException并且我必须将它包装在 try catch 中,并且代码最终看起来比它可能需要的要可怕得多。

4

5 回答 5

13

如果你知道你正在处理一个StringReader你会扔掉的东西,我看不出有任何理由关闭它。我无法想象在关闭它之后你会持有对它的引用的任何原因,因此设置null为垃圾收集的字符串没有真正的好处。如果您正在创建一个采用 a 的方法,Reader那么关闭它可能是有意义的,因为您不知道基础类型。

于 2011-05-25T09:14:11.520 回答
6

它的作用不止于此。如果我可以引用 JavaDoc:

/**
 * Closes the stream and releases any system resources associated with
 * it. Once the stream has been closed, further read(),
 * ready(), mark(), or reset() invocations will throw an IOException.
 * Closing a previously closed stream has no effect.
 */

所以是的,你应该关闭那个阅读器。不是为了资源,而是为了好的风格和可能跟随你的程序员。你不知道这个实例将被传递到哪里以及其他人会尝试用它做什么。有一天,您可能还会选择更改接口并接受任何 Reader 实现,在这种情况下,您可能会处理需要调用 close() 以释放资源的 Reader。

因此,一旦你完成它,防止进一步(可能是错误的)使用这个实例是一种很好的风格。而且由于它没有伤害,它只会防止将来可能出现的错误。

编辑: 既然你说你的 close() 方法正在声明它可能会抛出的异常,我会说你需要调用 close() 因为 StringReader.close() 不会抛出异常。但是, Reader.close() 可以。因此,您已经允许 Reader 的其他实现,因此您必须关闭它,因为您不知道最终会获得哪些 Reader 实现。如果我们正在谈论永远不会离开该范围的三行代码,请声明您的变量 StringReader 并调用 close (在这种情况下不进行异常处理)。

于 2011-05-25T09:21:14.890 回答
4

虽然严格来说没有必要,因为 StringReader 只保留一个字符串,作为一种良好的形式,无论如何关闭所有阅读器总是一个好主意。今天,您的代码可能正在使用 StringReader,但如果您将其更改为另一个确实需要关闭的 Reader,则您的代码没有关闭将是错误的,而您的 w/ 关闭会很好。

于 2011-05-25T09:24:36.060 回答
1

如果您的变量具有 type StringReader,而不是 ,则不需要捕获异常Reader,因为StringReader#close()不会引发异常:只会Reader#close()。因此,您可以使用try-with-resources自动关闭阅读器,而无需使用样板来处理不会发生的异常。Reader#close()throwingIOException意味着子类型可以抛出这种类型的异常,而不是它们必须。这是您要声明具有子类型而不是超类型的变量的罕见情况之一;请参阅在 java 中使用接口或类型进行变量定义?更多。

因此,我建议以下内容,它只需要一层嵌套,这对于资源来说是同等的:

try (StringReader reader = new StringReader(string)) {
    // Do something with reader.
}

但是,关闭 a 没有什么价值StringReader,因为它不包含外部资源(例如,只有 Java 管理的内存,而不是文件句柄或本机内存),所以可以省略它,尽管我建议您发表评论说明为什么这是安全的,因为否则不关闭读者是令人惊讶的。正如您所注意到close()的,根据 JDK 8 来源,只需将该字段清空:StringReader.java:198。如果你想避免嵌套和关闭,你可以这样写:

// Don't need to close StringReader, since no external resource.
StringReader reader = new StringReader(string);
// Do something with reader.

...或(使用更通用的变量类型):

// Don't need to close StringReader, since no external resource.
Reader reader = new StringReader(string);
// Do something with reader.

正常的 try-with-resources 在这里有效,因为它StringReader#close()会覆盖Reader#close()并仁慈地声明它不会 throw IOException

请注意,String Writer并非如此:确实声明它 throws ,尽管它是一个 nop!这大概是为了向前兼容,所以它可能会在未来的实现中抛出异常,尽管这不太可能。请参阅不会关闭 stringwriter 导致泄漏的回答?.StringWriter#close() IOException

在这种情况下(如果该方法没有抛出异常,但接口声明它可以),编写这个的紧凑方法,你大概是在暗示,是:

Reader reader = new StringReader(string);
try {
    // Do something with reader, which may or may not throw IOException.
} finally {
    try {
        reader.close();
    } catch (IOException e) {
        throw new AssertionError("StringReader#close() cannot throw IOException", e);
    }
}

这一级别的样板文件是必要的,因为您不能只在整个 try 块上放置一个 catch,否则您可能会不小心吞下IOException代码主体抛出的一个异常。即使目前没有,将来也可能会添加一些,并且您希望编译器对此进行警告。另请注意AssertionError,记录当前行为的 . 也会掩盖由 try 语句的主体抛出的异常,尽管这绝不应该发生。如果这是替代方案,您显然最好省略close()并评论原因。

这个答案取决于您StringReader自己创建的事实;当然,如果您Reader从其他地方收到 a (例如作为工厂的返回类型),那么您需要关闭它并处理可能的异常,因为您不知道它可能拥有什么资源,并且它可能会抛出一个例外。

于 2015-08-30T22:39:33.230 回答
-1

如果您关闭流并释放与之关联的任何系统资源。关闭流后,进一步的 read()、ready()、mark() 或 reset() 调用将引发 IOException。关闭以前关闭的流没有效果。指定者:Closeable接口中的close指定者:类Reader中的close

于 2011-05-25T09:13:41.147 回答