如果您的变量 的类型为StringReader,而不是Reader,则您不需要捕获异常,因为StringReader#close() 不会引发异常:只有Reader#close() 会.因此,您可以使用try-with-resources 自动关闭阅读器,而无需使用样板来处理不会发生的异常。 Reader#close() throwing IOException 表示子类型可以抛出这种类型的异常,而不是它们必须。这是您要声明具有子类型而不是超类型的变量的罕见情况之一;更多信息请参见Use interface or type for variable definition in java?。
因此,我建议如下,它只需要一层嵌套,这对于资源来说是同等的:
try (StringReader reader = new StringReader(string)) {
// Do something with reader.
}
但是,关闭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() 并幸运地声明它不会抛出 IOException。
请注意 不是 StringWriter 的情况:StringWriter#close() 确实 声明它抛出 IOException,尽管它是不!这大概是为了向前兼容,所以它可能会在未来的实现中抛出异常,尽管这不太可能。见my answer
Will not closing a stringwriter cause a leak?.
在这种情况下(如果方法没有抛出异常,但接口声明它可以),编写这个的紧凑方法,你大概是在暗示,是:
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(例如,作为工厂的返回类型),那么您需要关闭它并处理可能的异常,因为您不知道它可能拥有什么资源,并且可能会抛出异常。