0

Have a look at this simple Java code:

class A {
    public static void main(String[] args) {
        final int x;
        try {
            throw new RuntimeException();
            x = 1;
        } finally {}
        x = 2;
        System.out.println("x: " + x);
    }
}

I'd expect it to print "x: 2".

A.java:6: unreachable statement
            x = 1;
            ^
A.java:8: variable x might already have been assigned
        x = 2;
        ^
2 errors

It says it wont compile because on line 8, x = 2 might reassign the final variable, but this is false because as it said above, the line x = 1 is unreachable, thus it will assign it for the first time, not reassign.

Why does the compiler give an error stating that "x might have already been assigned" when it knows that x has not been assigned?

Dog
  • 7,707
  • 8
  • 40
  • 74

6 Answers6

2

It is explained in the JLS chapter 16

[...] Similarly, every blank final variable must be assigned at most once; it must be definitely unassigned when an assignment to it occurs.

Such an assignment is defined to occur if and only if either the simple name of the variable (or, for a field, its simple name qualified by this) occurs on the left hand side of an assignment operator.

For every assignment to a blank final variable, the variable must be definitely unassigned before the assignment, or a compile-time error occurs.

So, JLS does not seem to care about unreachable code.

And concerning exceptions it says:

An exception parameter V of a catch clause (§14.20) is definitely assigned (and moreover is not definitely unassigned) before the body of the catch clause.

so the problem here is that x=1 and x=2 are both definitely assigned as

If a try statement does have a finally block, then these rules also apply:

V is definitely assigned after the try statement iff at least one of the following is true:

    V is definitely assigned after the try block and V is definitely assigned after every catch block in the try statement.

    V is definitely assigned after the finally block.

    V is definitely unassigned after a try statement iff V is definitely unassigned after the finally block.
Uku Loskit
  • 40,868
  • 9
  • 92
  • 93
  • An [*unreachable statement*](http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.21) is a compile-time error, as a "`throw` statement cannot complete normally." – trashgod Jul 01 '13 at 10:39
0

The first error is a result of, well, unreachable code. Once you throw the exception, the method is halted, and the next line can never be executed. You can fix the second error by simply removing the final modifier from x. But I must ask, why are you writing a program whose only purpose is to throw a RuntimeException?

Max Roncace
  • 1,277
  • 2
  • 15
  • 40
  • He can't fix the second error like that, everything after the `try`-block is unreachable. Or, rather, he can fix it but he will receive another unreachable-code-error. – arshajii Jun 30 '13 at 23:31
0

The java compiler can't look at things the same way we do as humans. It doesn't see cause and effect, only what is in error. And in this case it may be a good thing, because even if you fix one of the errors, the other will persist.

Martin Wickham
  • 442
  • 4
  • 9
0

It's probably a language definition issue. One area of the spec prohibits reassignment if it might have already been assigned. A different area discusses unreachable code.

The combination of the two is probably never really addressed.

Could you perhaps supply something that is a bit more representative of what you are really trying to accomplish?

Andy Davis
  • 1,393
  • 1
  • 13
  • 24
0

Looks like you are learning Java. The first error is because the compiler can see that execution of a block cannot continue after you throw an exception: control will jump to wherever the exception is caught. Other posters have explained the second error.

andy256
  • 2,821
  • 2
  • 13
  • 19
0

I've seen other cases that are less straightforward, for example something like:

final int x;
boolean b = ...;
if(b) {
   x = 1;
}
...
if(!b) {
   x = 2;
}

The easiest solution is to assign to a temporary non-final variable, then copy it to the final variable:

final int x;
int _x = 0;
boolean b = ...;
if(b) {
   _x = 1;
}
...
if(!b) {
   _x = 2;
}
x = _x;
Adam Crume
  • 15,614
  • 8
  • 46
  • 50