在你说这个问题已经被回答了很多次之前,这是我的代码片段:
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();
}
}