为啥 try-with-resources 不能与字段变量一起使用?
Posted
技术标签:
【中文标题】为啥 try-with-resources 不能与字段变量一起使用?【英文标题】:Why doesn't try-with-resources work with field variables?为什么 try-with-resources 不能与字段变量一起使用? 【发布时间】:2013-06-21 12:31:48 【问题描述】:这是我关于 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();
谁能解释一下为什么会有这个约定?
【问题讨论】:
【参考方案1】:在 try-with-resources 块的执行过程中,可以随时更改实例变量。这将破坏其不变量并阻止清理。请注意,出于同样的原因,局部变量是隐含的 final。
顺便说一句,一个更好的问题是,为什么Java 强制我们声明一个局部变量,即使我们没有在块中引用它。例如,C# 不需要这个。
更新:在第 9 版中,Java 不再强迫我们:
private final Some obj = new Some();
try (obj)
// obj captured in a hidden local variable, resource closed in the end
【讨论】:
【参考方案2】:我怀疑设计师认为使用字段是个坏主意,因为这会使对象逃离使用区域。即它仅在 try 块中有效,因此您应该无法在其他任何地方访问它。
【讨论】:
也可以这样逃走。关键是有一个 final 变量,它保证在 try-with-resources 结束之前保持相同的值。 @MarkoTopolniktry
字段是否已隐式设为最终字段?
是的,刚刚试过。在 try-with-resources 中声明的变量是隐式的 final。具体来说,Eclipse 给出了这个错误:“无法分配 try-with-resources 语句的资源 var
他们几乎肯定会将他们的 vars 保留为最终版本,除非他们特别需要更改。除此之外,它可能会阻止涉及可变变量的习语。令人难以置信的是,我从带有最终变量的代码中减少了多少认知压力!【参考方案3】:
Java Language Specification 中的Section 14.20.3 声明它仅适用于局部变量。
这是为什么?我的猜测是检查明确的赋值和转义(局部变量不会转义到另一个方法的范围内)。一个字段可以在类中的任何地方初始化。我的猜测是,通过验证它是一个局部变量,分析起来要简单得多。
【讨论】:
【参考方案4】:在 Java 9 中,他们增加了对带有变量的资源的 try 支持。
// 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
【讨论】:
【参考方案5】:首先,我认为拥有一个在多个地方使用的变量/资源是不好的做法。如果它没有在try
中打开,那么你以后不能关闭它,如果它在那里打开,那么你就不需要一个非局部变量。
这导致“第二个”:如果您已经打开了一个资源,那么您需要在其他地方明确关闭它,否则自动关闭将不知道它是否打开。
因此,恕我直言,只有按照规范中指定的方式处理它才有意义。
【讨论】:
【参考方案6】:从 Java 9 开始,无需在 try-with-resources 块中使用局部变量。见here。
【讨论】:
【参考方案7】:这可能与语言规范的一致性有关。 每当在两个括号之间声明一个变量时,它都被封装在内部,不能从外部访问:
anything
int var;
// cannot access var from here!
为什么要尝试 是一个例外?
【讨论】:
以上是关于为啥 try-with-resources 不能与字段变量一起使用?的主要内容,如果未能解决你的问题,请参考以下文章
1.9 try-with-resources 优先于try-finally
try-with-resources 调用 close() 失败
Redis分布式锁的try-with-resources实现
第9项:尽量使用try-with-resources而不是try-finally(Prefer try-with-resources to try-finally)