简体   繁体   English

在try / catch语句中有效地分配最终变量

[英]Assignment of effectively final variable in try/catch statement

The following code does not compile with javac 1.8.0_144 and ecj: 以下代码无法与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;
}

I am wondering if this a bug in the compiler. 我想知道这是否是编译器中的错误。 The definition of effectively final in the JLS is: JLS中有效最终的定义是:

Certain variables that are not declared final are instead considered effectively final: 某些未声明为final的变量实际上被认为是final:

  • A local variable whose declarator has an initializer (§14.4.2) is effectively final if all of the following are true: 如果满足以下所有条件,则其声明符具有初始化程序(第14.4.2节)的局部变量实际上是最终的:

    • It is not declared final. 它不是最终的。

    • It never occurs as the left hand side in an assignment expression (§15.26). 它永远不会出现在赋值表达式的左侧(第15.26节)。 (Note that the local variable declarator containing the (请注意,包含
      initializer is not an assignment expression.) 初始化程序不是赋值表达式。)

    • It never occurs as the operand of a prefix or postfix increment or decrement operator (§15.14, §15.15). 它永远不会作为前缀或后缀递增或递减运算符的操作数出现(第15.14、15.15节)。

  • A local variable whose declarator lacks an initializer is effectively final if all of the following are true: 如果满足以下所有条件,则其声明符缺少初始化程序的局部变量实际上是最终的:

    • It is not declared final. 它不是最终的。

    • Whenever it occurs as the left hand side in an assignment expression, it is definitely unassigned and not definitely assigned before the assignment; 每当它出现在赋值表达式的左侧时,它肯定是未赋值的,而且在赋值之前也没有赋值; that is, it is definitely unassigned and not definitely assigned after the right hand side of the assignment expression (§16 (Definite Assignment)). 也就是说,在赋值表达式的右侧(第16节(确定赋值))之后,它肯定是未赋值的,也没有确定赋值。

    • It never occurs as the operand of a prefix or postfix increment or decrement operator. 它永远不会作为前缀或后缀递增或递减运算符的操作数出现。

  • A method, constructor, lambda, or exception parameter (§8.4.1, §8.8.1, §9.4, §15.27.1, §14.20) is treated, for the purpose of 出于以下目的,处理了方法,构造函数,lambda或异常参数(第8.4.1节,第8.8.1节,第9.4节,第15.27.1节,第14.20节)。
    determining whether it is effectively final, as a local variable 确定它是否最终有效,作为局部变量
    whose declarator has an initializer. 其声明程序具有初始化程序。

My reading is that in clause 2, the assignments in the try/catch block are allowed because fileSize is definitely unassigned before the assignment. 我的理解是,在第2节中,允许在try / catch块中进行赋值,因为fileSize在赋值之前肯定是未赋值的。

I think the reasoning to explain the rejection of the code is: 我认为解释拒绝代码的原因是:

  • fileSize is definitely unassigned before the try block 在try块之前,绝对未分配fileSize
  • fileSize is assigned (definitely? It seems that 16.1.8 does not care about exceptions in the assignment) after fileSize = canThrow() 在fileSize = canThrow()之后,分配了fileSize(肯定吗?似乎16.1.8不在乎分配中的异常)
  • fileSize is assigned after the try block 在try块之后分配fileSize
  • fileSize is not definitely unassigned before the catch block, and thus not definitely unassigned before the assignment in the catch block. 在catch块之前不一定未分配fileSize,因此在catch块中分配之前不一定未分配fileSize。
  • thus, clause 2 of 4.12.4 does not apply here 因此,第4.12.4条第2款在此不适用

Is this correct? 这个对吗?

The definition of "Effectively final" states that adding a final modifier should not change anything. “有效最终”的定义指出添加final修饰符不应更改任何内容。 Let's do that and get a clearer error: 让我们这样做,得到一个更清晰的错误:

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

So this is the exact same case as Final variable assignment with try/catch (which also gives a workaround using a second final variable), namely the variable appears on the left of an assignment, which means it is not definitely unassigned. 因此,这与带有try / catch的Final变量赋值完全相同(这也提供了使用第二个final变量的解决方法),即该变量出现在赋值的左侧,这意味着它不一定是未赋值的。

(For good order try-catch has nothing to do with the issue: they merely argue that the catch exception parameter is considered final.) (对于良好顺序,try-catch与该问题无关:他们只是认为catch异常参数被认为是最终参数。)

The intention of being "effectively final" is founded on there being two threads with each a copy of the identically named variable. “有效最终”的意图是基于存在两个线程,每个线程都有一个同名变量的副本 The life times of those two threads/variables are different. 这两个线程/变量的生命周期不同。 They want to prevent change in one thread which would have needed some synchronisation and lifeliness check. 他们希望防止更改一个线程,而这需要进行一些同步和生命周期检查。

So they definitely do not want an assignment. 因此,他们绝对不希望作业。 As language design decision. 由语言设计决定。

Indeed an internal thread in canThrow could use fileSize being still 0 after the catch set the other variable fileSize to 42. I think you consider a raised exception to signify the other thread is dead. 事实上,在一个内螺纹canThrow could使用fileSize为仍为0捕捉其他变量设置后, fileSize42,我认为你考虑引发异常,以表示其他线程已经死了。

What you want in this case is a Future/FutureTask or such. 在这种情况下,您想要的是Future / FutureTask等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用try / catch进行最终变量分配 - Final variable assignment with try/catch 可以在catch中重新分配最终变量,即使赋值是try中的最后一个操作吗? - Could a final variable be reassigned in catch, even if assignment is last operation in try? Java 8 - 有效的最终变量,lambdas和try / catch / finally块 - Java 8 - effectively final variables, lambdas and try/catch/finally block 使用try / catch声明并初始化最终变量 - Using try/catch to declare and initialize a final variable 无法在try / catch中初始化静态最终变量 - can not initialize static final variable in try/catch 尝试Catch Final-final变量始终为null - Try Catch Final - final always has null in variable 为什么在 try-with-resources 语句之外声明的资源需要在 java 中是 final 或有效 final? - why resources declared outside the try-with-resources statement need to be final or effectively final in java? 问题:“用作尝试资源资源的变量应该是最终的或有效的最终” - Problem with: "Variable used as a try-with-resources resource should be final or effectively final" 变量没有在java中定义try catch return语句 - variable not defined in java try catch return statement java:如何声明final在try-catch块中初始化的变量? - java: how to declare final a variable that is initialized inside a try - catch block?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM