以下代码无法使用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;
}
我想知道这是否是编译器中的错误。 The definition of effectively final in the JLS是:
某些未声明为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
在赋值之前肯定是未分配的。
我认为解释拒绝代码的原因是:
这是对的吗?
答案 0 :(得分:2)
“有效最终”的定义指出添加final
修饰符不应改变任何内容。让我们这样做,并得到一个更明确的错误:
error: variable fileSize might already have been assigned
fileSize = 42;
^
因此,这与Final variable assignment with try/catch完全相同(也使用第二个最终变量提供了解决方法),即变量出现在赋值的左侧,这意味着它并非绝对未分配。
答案 1 :(得分:2)
(为了良好的顺序,try-catch与问题无关:他们只是认为catch异常参数被认为是final。)
意图是"有效的最终"建立在两个线程的基础上,每个线程都具有同名变量的副本。这两个线程/变量的生命周期是不同的。他们希望防止一个线程发生变化,这需要进行一些同步和生命检查。
所以他们绝对不想要任务。作为语言设计的决定。
canThrow could
中的内部线程使用fileSize
仍然为 后,将另一个变量fileSize
设置为42. 我认为你考虑一个引发的异常来表示另一个线程已经死亡。
在这种情况下,你想要的是 Future / FutureTask 等。