【问题标题】:Use resource in try with resource statement that was created before在尝试使用之前创建的资源语句中使用资源
【发布时间】:2017-05-03 13:21:20
【问题描述】:

从 Java 7 开始,我们可以将try 与资源一起使用:

try (One one = new One(); Two two = new Two()) {
    System.out.println("try");
} catch (Exception ex) { ... }

现在我的问题是,为什么我必须在try-statement 中创建对象?为什么我不允许在这样的语句之前创建对象:

One one = new One();
try (one; Two two = new Two()) {
    System.out.println("try");
} catch (Exception ex) { ... }

我没有看到任何原因,为什么这应该是一个问题。虽然我收到错误消息“此语言级别不支持资源引用”。我将我的 IDE (IntelliJ IDEA) 设置为 Java 8,这样应该可以工作。不允许这样做有充分的理由吗?

【问题讨论】:

  • 因为如果在构造函数中抛出异常,您将无法捕获它。
  • 是的,这可能是原因,我同意。我说得对吗,这只是他们做出的一个选择 - 本来可以允许在外部创建对象 - 我们只是不会捕获那里创建的异常 - 对吗?
  • try 在实例上没有意义,已经创建的实例中没有逻辑。但是,在其构建过程中,您可能需要处理一些例外情况。
  • 资源使用时有逻辑,所以可能会抛出异常。
  • try中不需要有构造函数,只需要局部变量声明和赋值即可:One one = new One(); try (One one2 = one) { ... }有效。

标签: java try-with-resources


【解决方案1】:

您不必在 try-with-resources 语句中创建对象,您只需声明一些实现AutoCloseable 的类型的局部变量。这些变量实际上是最终变量,并且作用域为 try 块,这允许编译器使用它们来生成清理所需的 close 样板。

FileInputStream f1 = new FileInputStream("test1.xml");
FileInputStream f2 = new FileInputStream("test2.xml");
// Don't need to create the resources here, just need to declare some vars
try (InputStream in1 = f1; InputStream in2 = f2) {
    // error; in1 is final
    in1 = new FileInputStream("t");
}

Better Resource Management with Java SE 7: Beyond Syntactic Sugar.

附录:从java 9开始,要求放宽了;如果原件实际上是最终的,则不必在 try 块中重新声明变量。

JEP 213

【讨论】:

  • 你有什么想法,为什么我们必须声明一个作用域为try-statement 的新变量?这对我来说似乎没有必要 - 有充分的理由吗?
  • 当然,编译器需要一个最终的本地引用来执行清理,但我想不出为什么如果我们被允许传入资源引用它就不能弥补一个原因。
  • 我想这里的想法是资源引用可能不是最终的,因此最好创建一个新的最终本地引用。自动创建一个可能是可能的,但可能会导致混乱。我很惊讶,在 try 块之外创建最终引用并将其提交也是不允许的,因为我认为这应该是有效的代码。为避免混淆,可能不再允许。
【解决方案2】:

其实是可以的:

One one = new One();
try (One temp = one; ....;) {

}

从 Java 9 开始,您甚至不需要声明额外的变量,而是可以直接使用该变量:

One one = new One();
try (one) {
    //...
}

但是,几乎没有充分的理由在 try-with-resources 之前创建资源。这可能是 try-with-resources 块最初要求您在资源列表中声明一个新变量的原因(这也很容易强制该变量是最终的)。然而,语言设计者认为灵活性在这里更为重要。

在 try-with-resources 块之前创建资源可能会导致细微的错误,因为如果在您进入块之前发生异常(例如,如果您在创建 One 和进入try-with-resources 块)。

通常你应该没有理由在资源关闭后访问它,所以你应该将范围限制在资源打开的时间(即 try-with-resources 块)。如果您确实需要在关闭资源后访问它,您可能需要考虑不同的设计,其中(可关闭)资源与关闭资源后所需的对象/数据分开,或者您需要使用嵌套尝试-with-resources 块。

一个例外,可能是如果你得到一个 AutoCloseable 传入,并且你的方法必须保证它在退出时关闭,但这通常是一种设计味道:打开资源的人也应该负责关闭它。

【讨论】:

    【解决方案3】:

    从 Java 9 开始,可以清理带有 final 引用的 try-resource 块,而无需在 try 块中重新声明变量。

    例如,

    final One one = new One();
    try (one) {
        System.out.println("try");
    } catch (Exception ex) { ... }
    

    Source:

    允许在 try-with-resources 语句中将有效最终变量用作资源。 Java SE 7 中的 try-with-resources 语句的最终版本需要为语句管理的每个资源声明一个新变量。这是该功能早期迭代的变化。 JSR 334 的公共审查草案讨论了从 try-with-resource 的早期草案审查版本进行更改的理由,该版本允许由语句管理的表达式。 JSR 334 专家组赞成对 try-with-resources 进行额外的改进:如果资源由 final 或有效的 final 变量引用,则 try-with-resources 语句可以在不声明新变量的情况下管理资源。这种由 try-with-resources 语句管理的受限表达式避免了导致删除通用表达式支持的语义问题。在专家组决定进行此改进时,发布时间表中没有足够的时间来适应更改。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-24
      • 1970-01-01
      • 1970-01-01
      • 2022-07-28
      • 1970-01-01
      • 2019-12-20
      • 2020-02-08
      相关资源
      最近更新 更多