理解Java 9中的try with resources增强



不要在中初始化资源,而是尝试使用资源块,如下所示:

try(FileWriter fw = new FileWriter ("java.txt")) {
//some operation
}catch (IOException ioe) {
ioe.printStackTrace ();
}

,我们现在可以将引用传递给try with resources block,我们希望自动关闭,如下所示:

FileWriter fw = new FileWriter ("java.txt");
try(fw) {
//some operation
}catch (IOException ioe){
ioe.printStackTrace ();
}

到目前为止,这一部分是清楚的。我的问题是,为什么我将在下一个示例中显示的代码不起作用?它与前一个编译得很好的示例有什么不同?

public class Test {
private FileWriter fileWriter;
public Test (FileWriter fileWriter) throws IOException {
this.fileWriter = fileWriter;
}
{
try(fileWriter) { //compile error:
//"Variable used as a try-with-resources resource should be final or effectively final""
}catch (IOException ioe){
ioe.printStackTrace ();
}
}
}

有人能帮我理解这条信息的意思吗?我不知道这里可能出了什么问题。我还尝试在fileWriter变量声明中放入final,但这并没有解决问题。

我得到以下编译器错误,与您的不匹配:

The blank final field fileWriter may not have been initialized

这是因为您在实例初始值设定项中引用了fileWriter,它在超类构造函数调用和显式构造函数调用之后执行,但在构造函数中的任何剩余代码之前执行。根据JLS第12.5节;创建新的类实例":

  1. 将构造函数的参数分配给此构造函数调用的新创建的参数变量。

  2. 如果此构造函数以同一类中另一个构造函数的显式构造函数调用(§8.8.7.1(开始(使用此(,则评估参数并处理构造函数调用递归地使用这五个步骤。如果该构造函数调用突然完成,然后此过程突然完成出于同样的原因;否则,继续执行步骤5。

  3. 此构造函数不是以同一类中另一个构造函数的显式构造函数调用开始的(使用This(。如果该构造函数用于Object以外的类,则构造函数将以显式或隐式调用超类构造函数(使用super(。评估论点和使用这些递归处理超类构造函数调用同样的五个步骤。如果构造函数调用突然完成,则该过程由于相同的原因而突然完成。否则继续执行步骤4。

  4. 执行该类的实例初始化器和实例变量初始化器,分配实例变量的值初始化程序到相应的实例变量,在它们在源代码中文本显示的从左到右的顺序为班级。如果执行这些初始化程序中的任何一个导致异常,则不处理进一步的初始化程序,并且过程突然结束,出现了同样的异常。否则继续执行步骤5。

  5. 执行此构造函数正文的其余部分。如果该执行突然完成,则对于同样的原因。否则,此过程将正常完成。

(粗体强调矿(

这意味着您的构造函数尚未向fileWriter分配任何内容,从而导致实际错误。

在初始化fileWriter之后,将try-with-resources块放置在构造函数中,或者将其移动到方法中。

这本质上意味着Java希望您确保传递给尝试使用资源的变量(在本例中为fileWriter(在分配后不会更改。如果变量可以更改(比如在try块本身内(,那么可能会出现各种未定义的行为。

从代码的角度来看,要实现这一点,请在fileWriter:的声明中添加final

public class Test {
private final FileWriter fileWriter;  // add 'final'
public Test (FileWriter fileWriter) throws IOException {
this.fileWriter = fileWriter;
}

// ... in some other method
private void foo() {
try(fileWriter) {
} catch (IOException ioe){
ioe.printStackTrace ();
}
}
}

最新更新