抓住Throwable进行清理是否可以?

Tre*_*kaz 4 java finally try-catch throwable

举个这样的例子:

public List<CloseableThing> readThings(List<File> files) throws IOException {
    ImmutableList.Builder<CloseableThing> things = ImmutableList.builder();
    try {
        for (File file : files) {
            things.add(readThing(file))
        }
        return things.build();
    } catch (Throwable t) {
        for (CloseableThing thing : things.build()) {
            thing.close();
        }
        throw t;
    }
}
Run Code Online (Sandbox Code Playgroud)

代码审查评论的出现是因为通常有一条规则不会捕获Throwable.进行此类仅故障清理的旧模式是:

public List<CloseableThing> readThings(List<File> files) throws IOException {
    ImmutableList.Builder<CloseableThing> things = ImmutableList.builder();
    boolean success = false;
    try {
        for (File file : files) {
            things.add(readThing(file))
        }
        success = true;
        return things.build();
    } finally {
        if (!success) {
            for (CloseableThing thing : things.build()) {
                thing.close();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我觉得这有点乱,并不完全明白它是否与捕捉Throwable有什么不同.在任何一种情况下,异常都会传播.在任何一种情况下,当可能发生OutOfMemoryError时,正在运行其他代码.

那么终于真的更安全吗?

mor*_*ano 8

ThrowableExceptionError的父类型,因此捕获Throwable意味着捕获异常和错误.Exception是你可以恢复的东西(比如IOException),一个更严重的错误,通常你不能轻易恢复(比如ClassNotFoundError)所以除非你知道你在做什么,否则捕获错误没有多大意义.


Ste*_*n C 7

抓住Throwable进行清理是否可以?

总之一句话......不.

问题是,如果你捕获并重新抛出Throwable,你必须声明该方法抛出Throwable...这将导致调用该方法的任何问题:

  • 调用者现在必须"处理"(可能传播)Throwable.
  • 程序员现在不会以编译器错误的形式从编译器获得任何关于已检查的异常的帮助.(当您"处理" Throwable时,将包括尚未处理的所有已检查和未检查的异常.)

一旦你开始沿着这条路走下去,它throws Throwable就像疾病一样通过呼叫层次传播......


关闭资源的正确方法是使用finally,或者如果您正在编写Java 7或更高版本,则使用"尝试使用资源",并使您的资源可自动关闭.

(在您的示例中,这有点棘手,但您可以扩展现有List类以创建"可关闭列表"类,其中该close()方法关闭所有列表成员.


确实,对于Java 7及更高版本,您可以放弃将封闭方法声明为仅抛出将被捕获的已检查异常.然而,捕捉Throwable进行清理并不是人们期望看到的.人们希望看到一个finally清理条款.如果你以一种时髦的方式做到这一点,你就会让你的代码更难阅读...而且这不是"好".即使你的方式更简洁也不行.

此外,您的版本将无法使用Java 6及更早版本进行编译.


简而言之,我同意您的代码的审核者.

我唯一同意的是,如果你的版本和finally版本都是"安全的",假设它们是正确实现的.(问题是程序员必须在你的情况下更加努力地认识到它是安全的......因为你编写了非惯用的方法.)