29

这是我关于 SO 的第一个问题,我很困惑还没有类似的问题!

所以问题是:

为什么 try-with-resources 不能与字段变量一起使用?

或者换句话说:为什么我总是需要一个局部变量呢?

这里有一些示例代码:

public class FileWriteTest {

    public FileWriter file;

    public void workingDemo() {

        try(FileWriter file = new FileWriter(new File("someFilePath")) {
            // do something
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void notWorkingDemo() {

        file = null;

        try(file = new FileWriter(new File("someFilePath")) {
            // do something
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

谁能解释一下为什么会有这个约定?

4

7 回答 7

19

在 try-with-resources 块的执行过程中,可以随时更改实例变量。这会破坏它的不变量并阻止清理。请注意,出于同样的原因,局部变量是隐含的最终变量。

顺便说一句,一个更好的问题是,为什么 Java强制我们声明一个局部变量,即使我们没有在块中引用它。例如,C# 不需要这个。

更新:在第 9 版中,Java 不再强迫我们:

private final Some obj = new Some();

try (obj) { 
  // obj captured in a hidden local variable, resource closed in the end
}
于 2013-06-21T12:36:49.390 回答
8

我怀疑设计师认为使用字段是个坏主意,因为这会使对象逃离使用区域。即它仅在 try 块中有效,因此您不应该能够在其他任何地方访问它。

于 2013-06-21T12:35:35.800 回答
4

Java 语言规范第 14.20.3 节声明它只适用于局部变量。

为什么是这样?我的猜测是检查明确的赋值和转义(局部变量不会转义到另一个方法的范围内)。一个字段可以在类中的任何地方初始化。我的猜测是,通过验证它是一个局部变量,分析起来要简单得多。

于 2013-06-21T12:36:23.660 回答
4

在 Java 9 中,他们增加了对 try with resources with variables 的支持。

    // Original try-with-resources statement from JDK 7 or 8
    try (Resource r1 = resource1;
         Resource r2 = resource2) {
        // Use of resource1 and resource 2 through r1 and r2.
    }

    // New and improved try-with-resources statement in JDK 9
    try (resource1;
         resource2) {
        // Use of resource1 and resource 2.
    }

https://blogs.oracle.com/darcy/more-concise-try-with-resources-statements-in-jdk-9

于 2018-02-16T16:37:35.493 回答
1

首先,我认为在多个地方使用变量/资源是不好的做法。如果它没有在 中打开try,那么你以后不能关闭它,如果它在那里打开,那么你就不需要一个非局部变量。这导致“第二个”:如果您已经打开了一个资源,那么您需要在其他地方明确关闭它,否则自动关闭将不知道它是否打开。

因此,恕我直言,只有按照规范中指定的方式处理它才有意义。

于 2013-06-21T13:26:15.580 回答
1

从 Java 9 开始,无需在 try-with-resources 块中使用局部变量。见这里

于 2021-09-21T10:30:33.990 回答
0

它可能与语言规范的一致性有关。每当在两个括号之间声明变量时,它都被封装在内部,无法从外部访问:

anything
{
int var;
}

// cannot access var from here!

为什么要尝试 { } 是一个例外?

于 2013-06-21T13:33:17.993 回答