看看这个简单的Java代码:
class A {
public static void main(String[] args) {
final int x;
try {
throw new RuntimeException();
x = 1;
} finally {}
x = 2;
System.out.println("x: " + x);
}
}
我希望它能打印“x:2”。
A.java:6: unreachable statement
x = 1;
^
A.java:8: variable x might already have been assigned
x = 2;
^
2 errors
它说它不会编译,因为在第8行,x = 2
可能重新分配最终变量,但这是假的,因为如上所述,行x = 1
无法访问,因此它将首次分配,而不是重新分配。
为什么编译器在知道尚未分配x
时会发出错误,指出“x可能已被分配”?
答案 0 :(得分:2)
在JLS第16章
中对此进行了解释[...]同样,每个空白的最终变量必须至多分配 一旦;在转让它时,它必须是绝对未分配的 发生。
这样的赋值被定义为当且仅当其中一个时发生 变量的简单名称(或者,对于字段,它的简单名称 由此限定)发生在作业的左侧 操作
对于空白最终变量的每个赋值,变量必须为 在赋值之前肯定是未分配的,或者是编译时错误 发生。
因此,JLS似乎并不关心无法访问的代码。
关于例外,它说:
catch子句(§14.20)的异常参数V肯定是 在身体之前分配(而且绝对不是未分配) 捕获条款。
因此问题在于x=1
和x=2
都明确指定为
如果try语句确实有finally块,那么这些规则也是如此 适用:
V is definitely assigned after the try statement iff at least one of the following is true: V is definitely assigned after the try block and V is definitely assigned after every catch block in the try statement. V is definitely assigned after the finally block. V is definitely unassigned after a try statement iff V is definitely unassigned after the finally block.
答案 1 :(得分:0)
第一个错误是代码无法访问的结果。抛出异常后,该方法将暂停,并且永远不会执行下一行。您只需从x中删除最终修饰符即可修复第二个错误。但我必须问一下,为什么要编写一个程序,其唯一目的是抛出RuntimeException?
答案 2 :(得分:0)
java编译器不能像人类那样查看事物。它没有看到因果关系,只看错了。在这种情况下,它可能是一件好事,因为即使您修复了其中一个错误,另一个也会持续存在。
答案 3 :(得分:0)
这可能是一个语言定义问题。该规范的一个区域禁止重新分配,如果它已被分配。另一个区域讨论了无法访问的代码。
两者的结合可能从未真正解决过。
你能否提供一些更能代表你真正想要完成的事情的东西?
答案 4 :(得分:0)
看起来你正在学习Java。第一个错误是因为编译器可以看到在抛出异常后无法继续执行块:控制将跳转到捕获异常的任何位置。其他海报解释了第二个错误。
答案 5 :(得分:0)
我见过其他不太直白的案例,例如:
final int x;
boolean b = ...;
if(b) {
x = 1;
}
...
if(!b) {
x = 2;
}
最简单的解决方案是分配一个临时的非最终变量,然后将其复制到最终变量:
final int x;
int _x = 0;
boolean b = ...;
if(b) {
_x = 1;
}
...
if(!b) {
_x = 2;
}
x = _x;