[英]Assignment of effectively final variable in try/catch statement
以下代码无法与javac 1.8.0_144和ecj一起编译:
private LongSupplier foo() {
long fileSize;
try {
fileSize = canThrow();
} catch (IOException e) {
fileSize = 42;
}
LongSupplier foo = () -> 1 + fileSize;
return foo;
}
我想知道这是否是编译器中的错误。 JLS中有效最终的定义是:
某些未声明为final的变量实际上被认为是final:
如果满足以下所有条件,则其声明符具有初始化程序(第14.4.2节)的局部变量实际上是最终的:
它不是最终的。
它永远不会出现在赋值表达式的左侧(第15.26节)。 (请注意,包含
初始化程序不是赋值表达式。)它永远不会作为前缀或后缀递增或递减运算符的操作数出现(第15.14、15.15节)。
如果满足以下所有条件,则其声明符缺少初始化程序的局部变量实际上是最终的:
它不是最终的。
每当它出现在赋值表达式的左侧时,它肯定是未赋值的,而且在赋值之前也没有赋值; 也就是说,在赋值表达式的右侧(第16节(确定赋值))之后,它肯定是未赋值的,也没有确定赋值。
它永远不会作为前缀或后缀递增或递减运算符的操作数出现。
出于以下目的,处理了方法,构造函数,lambda或异常参数(第8.4.1节,第8.8.1节,第9.4节,第15.27.1节,第14.20节)。
确定它是否最终有效,作为局部变量
其声明程序具有初始化程序。
我的理解是,在第2节中,允许在try / catch块中进行赋值,因为fileSize
在赋值之前肯定是未赋值的。
我认为解释拒绝代码的原因是:
这个对吗?
“有效最终”的定义指出添加final
修饰符不应更改任何内容。 让我们这样做,得到一个更清晰的错误:
error: variable fileSize might already have been assigned
fileSize = 42;
^
因此,这与带有try / catch的Final变量赋值完全相同(这也提供了使用第二个final变量的解决方法),即该变量出现在赋值的左侧,这意味着它不一定是未赋值的。
(对于良好顺序,try-catch与该问题无关:他们只是认为catch异常参数被认为是最终参数。)
“有效最终”的意图是基于存在两个线程,每个线程都有一个同名变量的副本 。 这两个线程/变量的生命周期不同。 他们希望防止更改一个线程,而这需要进行一些同步和生命周期检查。
因此,他们绝对不希望作业。 由语言设计决定。
事实上,在一个内螺纹canThrow could
使用fileSize
为仍为0捕捉其他变量设置后, fileSize
到42,我认为你考虑引发异常,以表示其他线程已经死了。
在这种情况下,您想要的是Future / FutureTask等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.