Java“空白最终字段可能尚未初始化”方法中抛出异常

问题描述 投票:0回答:5

我有一些代码,例如:

final int var1;    

if ( isSomethingTrue ) {

   var1 = 123;

} else {
   throwErrorMethod();
}

int var2 = var1;

并且 throwErrorMethod 的定义类似于:

private void throwErrorMethod() throws Exception{

   throw new Exception();

}

我收到

blank final field may not have been initialized
语句的
var2 = var1
编译错误。如果我内联该方法,编译就可以了!

  1. 编译器没有看到调用方法上的
    throws Exception
    吗?
  2. 为什么出现带有
    may
    字样的错误会停止编译?!?
java compiler-errors compiler-warnings
5个回答
19
投票
  1. 不,编译器无法确定

    throwErrorMethod
    永远不会正常完成。规范中没有任何内容表明它应该这样做。不幸的是,没有办法表明一个方法永远不会正常返回。

  2. 这只是“可能”,因为有一个潜在的执行路径不会初始化变量。这种执行路径的存在被定义为错误。

您可能会发现 Eric Lippert 的这两篇博客文章(第 1 部分第 2 部分)很有趣。这是关于 C# 而不是 Java,但原理是一样的。


7
投票

例外就应该是例外。它并不假设总是抛出异常。

编译器使用“

may
”一词,因为它无法判断您是否可以访问未初始化的变量。此外,您可以更改该方法的功能而无需重新编译此类,并且它所做的任何假设都是不正确的。

如果你想总是抛出异常,你可以这样做

final int var1;    

if ( isSomethingTrue ) {

   var1 = 123;

} else {
   throw exceptionMethod();
}

int var2 = var1;

// later
public Exception exceptionMethod() {
    return new Exception("Complex-Exception-String");
}

1
投票

编译器不会执行您期望的那种检查。 它无法确定

throwErrorMethod
实际上每次都会抛出异常。 因此,它假设可以进入您的
else
子句,调用
throwErrorMethod
,从该方法返回,然后不初始化 var1
(必须初始化)。


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

} else { throw createErrorMethod(); }

其中

createErrorMethod()

 被声明返回某种 Throwable。


0
投票
声明“抛出异常”的方法不必在任何运行路径中抛出此异常。因此,编译器不知道该方法是否总是会抛出异常,并且也假设正常终止。因此,可能是

var1

 未初始化。

© www.soinside.com 2019 - 2024. All rights reserved.