try-catch和final变量

11

我有一个非常愚蠢的问题要问你 :)

比如,我有以下代码片段:

class MyClass {

    public static void main (String[] args) {

        final String status;

        try {
            method1();
            method2();
            method3();
            status = "OK";
        } catch (Exception e) {
            status = "BAD"; // <-- why compiler complains about this line??
        }

    }

    public static void method1() throws Exception {
        // ...
    }

    public static void method2() throws Exception {
        // ...
    }

    public static void method3() throws Exception {
        // ...
    }

}
问题在这里:为什么编译器抱怨这行代码?
IntelliJ IDEA说:变量'status'可能已经被赋值
但是,据我所见,在异常情况下我们永远不会到达设置status =“OK”的那一行代码。因此,status变量将是BAD,一切应该都没问题。如果我们没有任何异常,那么我们就会得到OK。而且我们只会一次性地设置这个变量。
对此有什么想法吗?
谢谢你的帮助!

1
编译器并不是那么聪明,如果你声明一个方法可能会抛出异常,编译器就不会费力去检查它,为了简单起见,它不允许这种情况发生。 - Toumash
2个回答

11

Java编译器看不到像我们一样的东西 - 即 status 要么被设置为 "OK",要么被设置为 "BAD"。它假设 status 可以被设置,并且抛出异常,在这种情况下,它会被赋值两次,从而导致编译器生成错误。

为了解决这个问题,在 try-catch 块中为其分配一个临时变量,然后在之后仅将 final 变量分配一次。

final String status;
String temp;

try {
    method1();
    method2();
    method3();
    temp = "OK";
} catch (Exception e) {
    temp = "BAD";
}

status = temp;

我认为这仍然是有效的错误,如果此线程在赋值后被中断并抛出“InterruptedException”会怎样? - jmj
1
@JigarJoshi 它不能抛出 InterruptedException(也许是其他什么异常,但不是那个异常,在这段代码中可能不会出现)。 - Sotirios Delimanolis
如果这是在单独的线程中,并且在interrupt()上被调用。 - jmj
2
@JigarJoshi 然后中断标志将在“线程”上设置。只有当线程在IO(或类似的东西:锁等)上被阻塞时,才会发生InterruptedException。 - Sotirios Delimanolis
@Sotirios 你是对的 - 谢谢! - jmj

2
如果导致异常的代码出现在status = "OK"之后,会怎么样呢?你遇到错误的原因似乎很明显。
以此为例:
final String status;

try {
    status = "OK":
    causeException();
}catch(Exception e) {
    status = "BAD";
}

void causeException() throws Exception() {
    throw new Exception();
}

这将导致重新分配变量,这就是为什么会出现错误的原因

2
该变量是final的。禁止重新分配。 - swinkler
5
我理解您想表达的意思。错误发生是因为上面显示的代码是可行的。现在的StackOverflow怎么了? - Dioxin

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