如何避免“本地变量可能未初始化”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(); } }