66

参考我的问题java.util.concurrent.locks.Lock 的 AutoCloseable 包装器中是否存在任何风险?,我想知道为什么 try-with-resource-statement 需要一个命名的局部变量。

我目前的使用情况如下:

try (AutoCloseableReentrantReadWiteLock.Lock l = _lock.writeLock()) {
    // do something
}        

该变量l在 try 块内未使用,只会污染命名空间。据我所知,类似的 C#using语句不需要局部命名变量。

是否有任何原因无法支持以下内容,匿名局部变量在 try 块结束时关闭?

try (_lock.writeLock()) {
    // do something
}        
4

4 回答 4

14

@McDowell 评论中的链接揭示了 Joe Darcy 在博客文章评论中的正确答案,他领导了引入 try-with-resources 声明的 Java 技术规范:

回到 JDK 7,我们从一个 try-with-resources 结构开始,它允许对资源使用通用表达式,包括方法调用。然而,专家组通过初稿审查 ( http://jcp.org/aboutJava/communityprocess/edr/jsr334/index.html ) 发现,

“[对try-with-resources statemenbt]未来可能发生的变化是放弃对将资源指定为通用表达式的支持。允许将通用表达式用作资源会导致非平凡的规范和实现复杂性。一个受限的表达式可以是一个标识符或 PrimaryNoNewArray 可能就足够了。即使是更严格的仅允许标识符的限制也可以提供几乎所有额外的效用,即在低得多的边际实现中允许完整表达式(过度强制声明新资源变量),并且规范影响。”

在 JDK 7 结束时,我们想要的是资源的新变量声明或现有的最终/有效最终变量。我们只有 7 个时间提供前者;在 9 中,我们也提供后者。

于 2016-01-12T12:36:28.783 回答
8

在他们考虑的用例中,大多数都需要访问块内的资源,例如,打开文件-读/写文件-关闭文件。如果他们认为有很多用例没有使用局部变量,他们就不会做出这个设计决定。

至于为什么 Lock 不能自动关闭,我认为 Doug Lea 并不太关心语法问题,他专注于解决难题。其他人总是可以在他的实用程序之上添加语法糖。

展望未来,try-with-resource 可能会过时,取而代之的是 lambda。例如

lock.withLock( ()->{ execute-while-holding-the-lock; } );
于 2013-05-16T15:03:53.667 回答
4

尽管我希望不是这样,但其背后的基本原理是 try-with-resources 严格用于对必须处理的项目的操作。它需要一个命名变量,因为它希望您在块内时对该变量执行某些操作。我想这就像编译器说“如果你不打算实际使用资源,你为什么要尝试使用资源?”

现在你和我都非常清楚,我们不想实际使用该资源:相反,我们只想确保在使用完它时将其关闭,这样我们就不会让开发人员四处锁定系统。但就像很多事情一样,他们必须做出设计决定,而且我们是少数,我们没有得到这个功能。

于 2013-06-27T21:54:17.610 回答
0

我认为无法使用局部变量是 try-with-resource 的触发因素。

在 java 1.7 之前,您必须编写如下内容:

InputStream in = null;
try {
    in = ....;
} finally {
    if (in != null) {
        in.close();
    }
}

这里有2个缺点:

  1. finally块很烦人,并且对于每个关闭资源都必须是空安全的
  2. 我们必须声明块外的资源才能在finally块中访问它们。因此,我们扩大了可访问变量的范围,这是不好的做法。

Try-with-resource 语法解决了这两个问题:

  1. finally根本不需要块。
  2. 资源变量只能在try块中访问,即应该知道的地方。

这就是为什么可关闭资源必须是本地的。否则,try-with-resource 语法的主要缺点之一是“禁用”。

于 2013-05-16T13:39:57.413 回答