Java try/catch语句中最终变量的赋值

Java try/catch语句中最终变量的赋值,java,lambda,language-lawyer,final,jls,Java,Lambda,Language Lawyer,Final,Jls,以下代码不使用JavaC1.8.0_144和ecj编译: private LongSupplier foo() { long fileSize; try { fileSize = canThrow(); } catch (IOException e) { fileSize = 42; } LongSupplier foo = () -> 1 + fileSize; return foo; } 我想知道这是否

以下代码不使用JavaC1.8.0_144和ecj编译:

private LongSupplier foo() {
    long fileSize;
    try {
        fileSize = canThrow();
    } catch (IOException e) {
        fileSize = 42;
    }

    LongSupplier foo = () -> 1 + fileSize;
    return foo;
}
我想知道这是否是编译器中的错误。是:

某些未声明为最终变量的变量实际上被视为最终变量:

如果以下所有条件均为真,则声明符具有初始值设定项§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肯定是未赋值的

我认为解释代码被拒绝的理由是:

在try块之前,文件大小肯定是未分配的 是否明确指定了文件大小?16.1.8似乎不关心fileSize=canThrow之后的赋值中的异常 文件大小是在try块之后分配的 文件大小在catch块之前不一定是未分配的,因此在catch块中的分配之前也不一定是未分配的。 因此,第4.12.4条第2款在此不适用
这是正确的吗

有效final的定义指出,添加final修饰符不应改变任何内容。让我们这样做,得到一个更清晰的错误:

error: variable fileSize might already have been assigned
                    fileSize = 42;
                    ^

因此,这与使用第二个最终变量提供解决方法的情况完全相同,即变量出现在赋值的左侧,这意味着它肯定不是未赋值的。

对于良好的顺序,try-catch与问题无关:他们只是认为catch-exception参数是最终的

有效的最终目的是基于有两个线程,每个线程都有一个同名变量的副本。这两个线程/变量的生命周期不同。他们希望防止一个线程发生变化,这需要一些同步和生命检查

所以他们肯定不想要任务。作为语言设计的决策

实际上,在catch将另一个变量fileSize设置为42之后,canThrow中的内部线程可以使用fileSize仍然为0。我认为你会考虑一个引发异常的情况,表示另一个线程已经死亡。
在这种情况下,您需要的是一个未来的任务或类似的任务。

我想说,文件大小实际上不是最终的,因为它可以在文件大小=0异常或其他情况下更改。i、 如果你做了这个变量,它就不会编译了final@PeterLawrey问题是javac总是接受代码,尽管它不应该接受。定义中的两个条款在这里都不适用,因此应该拒绝它,尽管我不认为在lambda声明之后没有赋值变量时不能这样做的技术问题。当initiaztion被删除时,javac仍然接受正确的IMHO代码,但ecj仍然拒绝它。我同意这种行为是合理的,尽管不符合规范,这意味着它可能在将来被破坏。抱歉,伙计们,我编译了错误的文件。ecj和javac都拒绝该代码,但我不确定这是否符合JLS。