如何避免“本地变量可能未初始化”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 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
被视为黑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);
即使由于abandonEverythingAndDie
而不会执行此添加的throw
,编译器也会知道来自此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可以在这里应用,取决于你的实际代码,exception捕获可以说是一种责任,所以我可能将这一方法分成两个。 一个不关心处理,一个只处理。
public void doBlah throws MyPanicException { final int x = blah(); System.out.println("x is " + x); } public void tryBlahOrDie { try{ doBlah(); } catch (MyPanicException e) { abandonEverythingAndDie(); } }