为什么程序不允许初始化静态final变量?

9
我发现了下面的Java代码,一开始看起来很不错,但是它永远无法编译:
public class UnwelcomeGuest {

    public static final long GUEST_USER_ID = -1;
    private static final long USER_ID;

    static {
        try {
            USER_ID = getUserIdFromEnvironment();
        } catch (IdUnavailableException e) {
            USER_ID = GUEST_USER_ID;
            System.out.println("Logging in as guest");
        }
    }

    private static long getUserIdFromEnvironment()
            throws IdUnavailableException {
        throw new IdUnavailableException(); // Simulate an error
    }

    public static void main(String[] args) {
        System.out.println("User ID: " + USER_ID);
    }
}//Class ends here


//User defined Exception
class IdUnavailableException extends Exception {

     IdUnavailableException() { }

}//Class ends here

以下是IDE显示的错误信息:

变量 USER_ID 可能已经被赋值。

静态常量变量赋值时是否存在问题?

3个回答

19

最终变量只允许在构造函数或初始化块中进行一次赋值。这段代码不能编译的原因是Java代码分析器看到了两个不互斥的分支对USER_ID进行了赋值。

解决此问题很简单:

static {
    long theId;
    try {
        theId = getUserIdFromEnvironment();
    } catch (IdUnavailableException e) {
        theId = GUEST_USER_ID;
        System.out.println("Logging in as guest");
    }
    USER_ID = theId;
}

2
@KshitijJain 最终变量只允许在构造函数或初始化块中进行一次赋值。 - Sergey Kalinichenko
3
但我期望编译器知道 try 块或 catch 块将被执行。因此,在运行时只应有一次赋值。那么为什么会出现这样的行为? - Rohit Jain
@Rohit:你问了一个非常好的问题。有人可以回答 Rohit 吗? - Kshitij Jain
2
@RohitJain 我怀疑他们采取了更简单的方法:如果作业不是try块中的最后一条指令,分析器就会是正确的,因为还有另一种可能性来触发异常。 - Sergey Kalinichenko
2
@RohitJain 我们不期望编译器知道try或catch会被执行,我们知道有一种情况下两者都会被执行,即当实际上存在异常时,因为已经对var进行了赋值(现在无法再次调用var进行赋值),所以会捕获异常,然后再次调用var进行赋值,从而导致问题。唯一的解决方法是按照dasblinkenglight所说,仅调用一次分配。 - Gianmarco
显示剩余2条评论

4
您在以下行中使用赋值运算符抛出异常的事实如下所示:
USER_ID = getUserIdFromEnvironment();

这意味着编译器认为有可能进行赋值操作,特别是考虑到它被声明为final


0

由于编译器给出了这种错误,表明变量已经在其他地方被创建(可能已经更改)。最好在代码中无论何处都更改变量的名称。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接