当前位置: 首页 > 知识库问答 >
问题:

在对象构建期间从与主体分开的try-with-资源中捕获错误

崔宜修
2023-03-14

我有一个可关闭类型,CloseableClass,它可以在其构造函数、方法甚至内部抛出IOError。我想使用try-with-resources,但在处理构建过程中的错误时仍然与使用过程中的错误不同(使用包括清理)。更好的是,我想编写可维护的代码。

假设您希望构造一个可关闭的类实例并将其与try-with资源语句一起使用。它可以在其构造函数和try-with资源主体中使用的方法中抛出IOException

import java.io.Closeable;
import java.io.IOException;
import java.util.Random;

public class CloseableClass implements Closeable {
    public CloseableClass() throws IOException {
        if (new Random().nextBoolean()) {
            throw new IOException();
        }
    }

    public void internetStuff() throws IOException {
        if (new Random().nextBoolean()) {
            throw new IOException();
        }
    }

    public void close() throws IOException {
        if (new Random().nextBoolean()) {
            throw new IOException();
        }
    }

    public static void main(String[] args) {
        try (CloseableClass closeable = new CloseableClass()) {
            closeable.internetStuff();
        }
        catch (IOException e) {
            System.out.println("Bad error!");
        }
    }
}

假设您想分别处理构造函数和主体中抛出的错误。有没有支持的方法可以做到这一点?在Python中,我会:

try:
    closeable = CloseableClass()
except IOException:
    print("Constructor error")
    return

try:
    with closeable:
        closeable.internet_stuff()
except IOException:
    print("Body error")

但在Java中,如果不为对象指定第二个名称,则无法执行以下操作:

CloseableClass closeable_;

try {
    closeable_ = new CloseableClass();
}
catch (IOException e) {            
    System.out.println("Constructor error!");
    return;
}

try (CloseableClass closeable = closeable_) {
    closeable.internetStuff();
}
catch (IOException e) {
    System.out.println("Body error!");
}

有人告诉我,这是“无法维护的代码”,主要是因为使用了“closeable\uu”,我对此表示同意。我希望避免使用try finally,因为如果使用try finally,您在模拟它时会遇到更糟糕的问题:

CloseableClass closeable;

try {
    closeable = new CloseableClass();
}
catch (IOException e) {            
    System.out.println("Constructor error!");
    return;
}

try {
    closeable.internetStuff();
}
catch (IOException e) {
    try {
        closeable.close();
    }
    catch (IOException ignore) {
        // Already dealing with this
    }

    System.out.println("Body error!");
}
finally {
    try {
        closeable.close();
    }
    catch (IOException e) {
        System.out.println("Body error!");
    }
}

注意,这需要第二次调用关闭(no op),测试类不遵守这一点(注意,自动关闭(AutoCloseable)不需要这一点,尽管关闭(AutoCloseable)需要这一点)。如果关闭时不能抛出,但不会抛出太多,这会更好一些。

基本上问题是

  • 关闭可以抛出
  • 在处理IOException之前关闭以防止打印“身体错误!”两次
  • 如何让它与来自try with资源的多个初始化程序一起工作并不明显
  • 无论如何,您最终都会复制代码。

我是被迫生活在“无法维护的代码”中,还是忽略了一个处理这个问题的好方法?


共有3个答案

戴高远
2023-03-14

从Java9开始,try-with-资源已经接受了“有效的最终”变量,因此您不需要重新分配变量。

CloseableClass closeable;

try {
    closeable = new CloseableClass();
}
catch (IOException e) {            
    System.out.println("Constructor error!");
    return;
}

try (closeable) {
    closeable.internetStuff();
}
catch (IOException e) {
    System.out.println("Body error!");
}
单勇
2023-03-14

一种解决方案是定义一种方法,将初始化错误封装在自定义异常类型中,然后使用该方法确定错误发生的时间。

private CloseableClass createCloseable() throws CloseableCreateException{
    try {
        return new CloseableClass();
    } except (IOException e) {
        throw new CloseableCreateException(e);
    }
}
try (CloseableClass closeable = initCloseable()) {
    closeable.internetStuff();
} catch (CloseableCreateException e) {
    System.out.println("Constructor error!");
} catch (IOException e) {
    System.out.println("Body error!");
}

另一个简单但有点不优雅的解决方案是使用布尔标志:

boolean init = true;
try (CloseableClass closeable = new CloseableClass()) {
    init = false;
    closeable.internetStuff();
} catch (IOException e) {
    if (init) {
        System.out.println("Constructor error!");
    } else {
        System.out.println("Body error!");
    }
}
凌俊材
2023-03-14
匿名用户

'注意,这需要第二次调用close以成为no op'-不,您不需要在catch块中执行close(),因为最后总是要执行。如果使用类似于系统的调用终止JVM,则只会在catch中使用close()block。exit()在捕捉块中。通常,您会从catch时钟向调用方抛出异常,但您将在大部分时间内最终执行清理。

尝试与资源更好,但您可以使用抛出的Exception的类型和描述来破译错误的内容和位置。

编辑

据我所知,我建议:

1) 试用资源:

try(Resource resource = new Resource()){
    // use resource.
}catch(Exception e){
    // handle exception.
    // OR better to throw exception to caller.
    throw e;
}

2) 传统风格:

Resource resource = null;
try{
    resource = new Resource();
    // use resource
}catch(Exception e){
    // handle exception.
    // OR better to throw exception to caller.
    throw e;
} finally {
   if(resource != null){
       try{
           resource.close();
       } catch(Exception e){
           // most of time you wont or cant do anything here.
       }
   }
}

 类似资料:
  • 在此Java程序示例中: 当在静态方法example()的正文中抛出OutOfMemoryError错误时,在终止静态方法example()之前,连接“con”和语句“stmt”是否会自动关闭,尽管没有任何“cat”捕获这些错误,因此在main()的其余代码中,是否确定这两个对象已关闭? 谢谢

  • 考虑来自Java文档的以下代码。 根据Java文档, 在示例readFirstLineFromFile中,如果从try块和try with resources语句抛出异常,则方法readFirstLineFromFile抛出从try块抛出的异常;禁止从try with resources块引发的异常。 另一方面,也提到了 由于BufferedReader实例是在try with resource语

  • 我有一个文件位于/res/introducted。xml。我知道我可以通过两种方式访问它: 1) R.引入的资源 2)一些绝对/相对URI 我正在尝试创建一个File对象以将其传递给特定的类。我该怎么做?

  • 我编写代码并使用CompatResources获取字体并设置为TypeFace以查看错误Fabric.io报告了一些崩溃。 由android引起。所容纳之物无法检索res.Resources$NotFoundException字体资源ID#0x7f090000。 这是我的代码: 谢谢你的帮助。

  • 我有下面的方法,它使用Apache Commons Http客户机向给定的URI发送异步GET,并返回Future和响应。 CloseableHttpAsyncClient实现了Closeable,因此我使用try/resource结构。 下面您可以看到其用法: 问题是,当我调用get on a future时,它不会返回所需的HttpResponse。如果我使用重载的get()方法,它将一直等待

  • id String - 调用[navigator.webkitGetUserMedia]时可用作 chromeMediaSourceId约束的窗口或屏幕的标识符。 标识符的格式为 window:XX或 screen:XX,其中 XX是一个随机生成的数字。 name String - 屏幕源将被命名为 Entire Screen 或 Screen <index>,而窗口源的名称将匹配窗口标题。 th