0

Have a look at this simple Java code:

final class A {
    public static void main(String[] args) {
        int x = 3;
        boolean b;
        switch(x) {
            case 1:
                b = true;
                break;
            default:
                throw new RuntimeException();
        }
        System.out.println("b: " + b);
    }
}

It assigns a b a value in the switch, but in the default case, throws an exception. Of course in real code, x would be computed in a more complex way.

$ javac A.java && java A
Exception in thread "main" java.lang.RuntimeException
    at A.main(A.java:10)

Fails when it runs as expected.

One would like to factor this exception throwing into a function to avoid typing the same thing over and over:

final class A {
    private static final void f() {
        throw new RuntimeException();
    }
    public static void main(String[] args) {
        int x = 3;
        boolean b;
        switch(x) {
            case 1:
                b = true;
                break;
            default:
                f();
        }
        System.out.println("b: " + b);
    }
}

However, this doesn't work:

$ javac A.java && java A
A.java:15: variable b might not have been initialized
        System.out.println("b: " + b);
                                   ^
1 error

It's complaining that b might not be initialized, even though it's clearly even though this is equivalent to the previous code. Why?

Dog
  • 7,707
  • 8
  • 40
  • 74

2 Answers2

0

The compiler's code reachability analysis is not omniscient.
For example, it does not look inside function calls to check whether they can actually return.

Therefore, it doesn't know that f() will throw an exception, so it think that the println() call is reachable and complains about it.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
0

The Answers of @Slaks and @dasblinkenlight correctly point out the cause of the problem. But they both imply (or could be read as implying) that it is the compiler or compiler writer's fault.

In fact, the Java compiler is only implementing the definite initialization rules as specified in the JLS. It is those rules say that b is not definitely initialized.

If someone was to implement a "smarter" Java compiler that figured out the exception was always thrown ... and allowed the code to compile ... you'd have the problem of one compiler accepting code that another compiler said was illegal. That would be a BAD THING for source code portability.

The bottom line is that your code won't compile because the Java spec says it shouldn't compile.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Why would you run code compiled from another machine? To save time? Java compiler doesn't do anything advanced and it takes seconds to compile hundreds of classes. – Dog May 05 '13 at 02:43
  • @Dog - I don't understand your point. Do you think that it would be good for different compilers to give different answers for the same source code? Do you think that people shouldn't be able to choose which compiler / java implementation they use? – Stephen C May 05 '13 at 02:49
  • No I thought you were implying it would be a bad thing for Java compilers to be able to compile my code because it would violate the spec and run on someone else's JVM bypassing the check. However that would be the runner's fault for running code compiled by someone else. – Dog May 05 '13 at 03:11
  • What I'm saying is that it would be a bad thing for one compiler to say "valid" and another to say "invalid" for the same source code. That means you could have to *change the code* to get it to compile. That is not acceptable in a language where portability is one of the main selling points. That is why the "definite initialization" rules are specified so strictly. – Stephen C May 05 '13 at 11:12