如何避免 "local variable may not have been initialized" Java 编译错误?(是的,认真的!



在你说这个问题已经被回答了很多次之前,这是我的代码片段:

final int x;
try {
x = blah(); 
} catch (MyPanicException e) {
abandonEverythingAndDie();
}
System.out.println("x is " + x);

如果调用abandonEverythingAndDie()具有结束整个程序执行的效果(例如因为它调用了System.exit(int)),则每当使用x时,它总是被初始化。

在当前的Java语言中,有没有一种方法可以让编译器对变量初始化感到满意,方法是通知编译器abandonEverythingAndDie()是一个永远不会将控制权返回给调用者的方法?

不想

  • 删除final关键字
  • 在声明时初始化x
  • 也不要将println置于try...catch块的范围内。

通过向编译器提供一点额外的信息来作弊:

final int x;
try {
x = blah();
} catch (MyPanicException e) {
abandonEverythingAndDie();
throw new AssertionError("impossible to reach this place"); // or return;
}
System.out.println("x is " + x);

你也可以让abandonEverythingAndDie()返回一些东西(只是语法上,它当然永远不会返回),并调用return abandonEverythingAndDie()

final int x;
try {
x = blah();
} catch (MyPanicException e) {
return abandonEverythingAndDie();
}
System.out.println("x is " + x);

和方法:

private static <T> T abandonEverythingAndDie() {
System.exit(1);
throw new AssertionError("impossible to reach this place");
}

甚至

throw abandonEverythingAndDie();

private static AssertionError abandonEverythingAndDie() {
System.exit(1);
throw new AssertionError("impossible to reach this place");
}

不,编译器只检查您的代码是否合法。在此上下文中,abandonEverythingAndDie被视为黑盒,编译器认为并非所有分支都涵盖变量的初始化。甚至下面的代码也不被编译器接受:

final int x;
try {
x = blah(); 
} catch (MyPanicException e) {
abandonEverythingAndDie();
System.exit(-1); // the System.exit() itself is treated as a blackbox :)
}
System.out.println("x is " + x);

换句话说,编译器不会为了编译程序而"考虑"可能的动态执行。

当然,最简单,最不笨拙的方法就是使用临时变量...

final int x;
int temp;   
try {
temp = blah(); 
} catch (MyPanicException e) {
abandonEverythingAndDie();
}
x = temp;
System.out.println("x is " + x);

简单。

我不确定这是否是一个选项,但您可以添加

throw new RuntimeException()

return;

在你的渔获中

final int x;
try {
x = blah(); 
} catch (MyPanicException e) {
abandonEverythingAndDie();
throw new RuntimeException(); // here
}
System.out.println("x is " + x);

即使这个添加的throw不会因为abandonEverythingAndDie而执行,编译器也会知道来自这个catch块的控制流不能回到System.out.println("x is " + x);所以它不需要初始化x

从逻辑上讲,如果失败了blah(),你为什么要对x做某事?x是未初始化的,这可能是危险的,因此Java可以防止这种情况。它以像c这样的旧语言无法做到的方式帮助你。因此,将println移到里面将是显而易见的解决方案。

try {
final int x = blah(); 
System.out.println("x is " + x);
} catch (MyPanicException e) {
abandonEverythingAndDie();
}

我认为 SRP 可以在这里应用,具体取决于您的实际代码,异常捕获可以说是一种责任,所以我可能会将这种方法分成两种。一个不在乎处理,一个只处理。

public void doBlah throws MyPanicException {
final int x = blah(); 
System.out.println("x is " + x);
}
public void tryBlahOrDie {
try{
doBlah();
} catch (MyPanicException e) {
abandonEverythingAndDie();
}
}

最新更新