在尝试使用之前创建的资源语句中使用资源

Use resource in try with resource statement that was created before

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

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

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

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

我看不出任何原因,为什么这应该是个问题。虽然我收到错误消息 "Resource references are not supported at this language level"。我将 IDE (IntelliJ IDEA) 设置为 Java 8,这样应该可以。不允许这样做有充分的理由吗?

您不必在 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

其实是可以的:

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 块)。如果您确实需要在资源关闭后访问它,您可能需要考虑不同的设计,其中(可关闭的)资源与关闭资源后您需要的 object/data 分开,或者您需要使用嵌套的 try-with-resources 块。

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

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

例如,

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

Source:

Allow effectively-final variables to be used as resources in the try-with-resources statement. The final version of try-with-resources statement in Java SE 7 requires a fresh variable to be declared for each resource being managed by the statement. This was a change from earlier iterations of the feature. The public review draft of JSR 334 discusses the rationale for the change from the early draft review version of try-with-resource which allowed an expression managed by the statement. The JSR 334 expert group was in favor of an additional refinement of try-with-resources: if the resource is referenced by a final or effectively final variable, a try-with-resources statement can manage the resource without a new variable being declared. This restricted expression being managed by a try-with-resources statement avoids the semantic issues which motivated removing general expression support. At the time the expert group settled on this refinement, there was insufficient time in the release schedule to accommodate the change.