8

Why won't Java let me assign a value to a final variable in a catch block after setting the value in the try block, even if it is not possible for the final value to be written in case of an exception.

Here is an example that demonstrates the problem:

public class FooBar {

    private final int foo;

    private FooBar() {
        try {
            int x = bla();
            foo = x; // In case of an exception this line is never reached
        } catch (Exception ex) {
            foo = 0; // But the compiler complains
                     // that foo might have been initialized
        }
    }

    private int bla() { // You can use any of the lines below, neither works
        // throw new RuntimeException();
        return 0;
    }
}

The problem is not hard to work around, but I would like to understand why the compiler does not accept this.

Thanks in advance for any inputs!

4
  • 2
    Well if you're catching the general Exception could it be possible for something to occur just after/during foo = x that would throw an exception? Maybe the compiler is "playing it safe"? Commented Apr 8, 2010 at 20:55
  • Well that is the question. But I really doubt that an assignment can result in an exception being thrown and still write a value to the variable. Commented Apr 8, 2010 at 20:57
  • 2
    Where you say "In case of an exception this line is never reached" I suspect that the compiler refuses to know your intentions to that level of granularity. So all it sees is foo being assigned twice. Perhaps the reason is that, this allows the compiler to optimize the code down to foo = bla(), since x is ultimately superfluous? Just speculating. Commented Apr 8, 2010 at 20:59
  • @greim Even if the compiler does reduce the assignment to foo = bla(); it is not possible to result in an exception and a correct assignment, since it is still two statements. I suspect that greim and FromCanada are right about the compiler playing safe (or being short sighted), because this is really a corner case which is only applicable if the assignment is the last non side effect free statement. Commented Apr 8, 2010 at 21:06

3 Answers 3

9
try {
    int x = bla();
    foo = x; // In case of an exception this line is never reached
} catch (Exception ex) {
    foo = 0; // But the compiler complains
             // that foo might have been initialized
}

The reason is because the compiler cannot infer that the exception can only be thrown before foo is initalized. This example is a special case where it is obvious that that is true, but consider:

try {
    int x = bla();
    foo = x; // In case of an exception this line is never reached...or is it?
    callAnotherFunctionThatThrowsAnException();  // Now what?
} catch (Exception ex) {
    foo = 0; // But the compiler complains
             // that foo might have been initialized,
             // and now it is correct.
}

To write a compiler to handle very specific cases like this would be an immense task - there are likely very many of them.

Sign up to request clarification or add additional context in comments.

1 Comment

I guess that is the problem here. The assignment must be the after any statements which may have side effects, which I guess would not be too hard to check, but on the other hand it's not really necessary as you can work around it easily (if a bit ugly).
2

To be a pedant, Thread.stop(Throwable) could throw an exception immediately after the try block assignment.

However, the rules with definite assignment and allied terms are complex enough. Check the JLS. Trying to add more rules would complicate the language and not provide significant benefit.

2 Comments

Wow, I didn't know about Thread.stop(Throwable). This must be the most evil method in the whole JDK...
+1 for mentioning the JLS. It's not just a quirk of the compiler implementation.
0

How about a thrown Error?

3 Comments

Right, try catching Throwable instead. If it will let you.
This would propagate out of the try-catch block and result in an exception at the caller of new FooBar();. So the final variable would never get written anyway. But in my case the compiler is complaining that the variable might get written twice, which is surely not the case.
Yes, you're right. I've misinterpreted the question. I'm actually also irritated by this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.