可以在catch中重新分配最终变量,即使赋值是try中的最后一个操作吗? [英] Could a final variable be reassigned in catch, even if assignment is last operation in try?

查看:181
本文介绍了可以在catch中重新分配最终变量,即使赋值是try中的最后一个操作吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我相信这里

final int i;
try { i = calculateIndex(); }
catch (Exception e) { i = 1; }

i 不可能已经分配如果控制到达catch-block。但是,Java编译器不同意并声称我可能已经分配了最终的本地变量

i cannot possibly have already been assigned if control reaches the catch-block. However, Java compiler disagrees and claims the final local variable i may already have been assigned.

还有一些吗?我在这里遗漏的细微之处,还是这只是Java语言规范用来识别潜在重新分配的模型的弱点?我主要担心的是诸如 Thread.stop()之类的东西,这可能会导致异常被凭空捏造,但我仍然看不出它是怎么回事在赋值后抛出,这显然是try-block中的最后一个动作。

Is there still some subtlety I am missing here, or is this just a weakness of the model used by the Java Language Specification to identify potential reassignments? My main worry are things like Thread.stop(), which may result in an exception being thrown "out of thin air," but I still don't see how it could be thrown after the assignment, which is apparently the very last action within the try-block.

如果允许的话,上面的成语会使我的许多方法变得更简单。请注意,此用例具有一流的语言支持,例如Scala,它一直使用 Maybe monad:

The idiom above, if allowed, would make many of my methods simpler. Note that this use case has first-class support in languages, such as Scala, which consistently employ the Maybe monad:

final int i = calculateIndex().getOrElse(1);

我认为这个用例可以作为一个很好的动机,允许一个特殊情况 i 在catch-block中肯定是未分配的

I think this use case serves as a quite good motivation to allow that one special case where i is definitely unassigned within the catch-block.

经过一番思考后,我更加确定这只是JLS模型的一个弱点:如果我在演示的例子中声明了公理, i 肯定是未分配的,它不会与任何其他公理或定理发生冲突。编译器在catch块中分配之前不允许读取任何 i ,因此无论 i 已被分配或不能被观察。

After some thought I am even more certain that this is just a weakness of the JLS model: if I declare the axiom "in the presented example, i is definitely unassigned when control reaches the catch-block", it will not conflict with any other axiom or theorem. The compiler will not allow any reading of i before it is assigned in the catch-block, so the fact whether i has been assigned to or not cannot be observed.

推荐答案

这是对支持论文的最有力论据的总结。在不违反一致性的情况下,不能放宽明确转让的现行规则(A),然后是我的反驳(B):

This is a summary of the strongest arguments in favor of the thesis that the current rules for definite assignment cannot be relaxed without breaking consistency (A), followed by my counterarguments (B):


  • A :在字节码级别,对变量的写入不是try-block中的最后一条指令:例如,最后一条指令通常是 goto 跳过异常处理代码;

  • A: on the bytecode level the write to the variable is not the last instruction within the try-block: for example, the last instruction will typically be a goto jump over the exception handling code;

B :但是如果规则声明在catch-block中肯定是未分配的,可能无法观察到它的值。不可观察的值与无值一样好;

B: but if the rules state that i is definitely unassigned within the catch-block, its value may not be observed. An unobservable value is as good as no value;

A :即使编译器声明 i 作为绝对未分配,调试工具仍然可以看到值;

A: even if the compiler declares i as definitely unassigned, a debug tool could still see the value;

B :实际上,调试工具总是可以访问未初始化的局部变量,这将在典型的实现上具有任意值。未初始化的变量与在实际写入发生后初始化完成的变量之间没有本质区别。无论此处考虑的特殊情况如何,该工具必须始终使用其他元数据来为每个局部变量知道该变量明确分配的指令范围,并且只允许在执行发现时观察其值本身在该范围内。

B: in fact, a debug tool could always access an uninitialized local variable, which will on a typical implementation have any arbitrary value. There is no essential difference between an uninitialized variable and a variable whose initialization completed abruptly after the actual write having occurred. Regardless of the special case under consideration here, the tool must always use additional metadata to know for each local variable the range of instructions where that variable is definitely assigned and only allow its value to be observed while execution finds itself within the range.

规范可以一致地接收更细粒度的规则,这将允许我发布的示例进行编译。

The specification could consistently receive more fine-grained rules which would allow my posted example to compile.

这篇关于可以在catch中重新分配最终变量,即使赋值是try中的最后一个操作吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆