编译器构造 - Java "blank final field may not have been initialized" 方法奇数引发异常



我有一些代码,如:

final int var1;    
if ( isSomethingTrue ) {
   var1 = 123;
} else {
   throwErrorMethod();
}
int var2 = var1;

而throwErrorMethod的定义如下:

private void throwErrorMethod() throws Exception{
   throw new Exception();
}

并且我得到var2 = var1语句的blank final field may not have been initialized编译错误。如果我内联这个方法,编译就没问题!

    编译器没有看到throws Exception上的方法调用?
  1. 为什么有may这个词的错误会停止编译?
  1. 不,编译器不确定throwErrorMethod将永远不会正常完成。规格书中并没有建议这样做。不幸的是,没有办法表明一个方法永远不会正常返回。

  2. 只是"可能",因为有一个潜在的执行路径没有初始化变量。存在这样的执行路径将被定义为错误。

您可以找到这两篇博客文章(第1部分;Eric Lippert的第2部分很有趣。它是关于c#而不是Java的,但原理是一样的。

异常应该是异常的。它不假设总是抛出异常。

编译器使用may这个词,因为它无法判断是否可以访问未初始化的变量。此外,您可以在不重新编译该类的情况下更改方法的功能,并且它所做的任何假设都是不正确的。

如果你想总是抛出一个异常,你可以做

final int var1;    
if ( isSomethingTrue ) {
   var1 = 123;
} else {
   throw exceptionMethod();
}
int var2 = var1;
// later
public Exception exceptionMethod() {
    return new Exception("Complex-Exception-String");
}

编译器不做您期望的那种检查。它不能确定throwErrorMethod实际上每次都抛出异常。因此,它假设可以进入else子句,调用throwErrorMethod,从该方法返回,然后不初始化var1(必须初始化)。

如果您想告诉编译器一定会抛出错误,但又不想内联构造错误的逻辑,您可以这样做:

} else {
   throw createErrorMethod();
}

其中createErrorMethod()被声明为返回某种Throwable

声明为"throws Exception"的方法不必在任何运行路径中抛出此异常。因此,编译器不知道该方法是否总是会抛出异常,并假设该方法也会正常终止。因此,var1可能没有初始化。

相关内容

最新更新