Java uninitialized variable with curiosity

I tried to come up with obscure test cases for an alternative open source JVM that I help with ( Avian ) when I came across an interesting bit of code, and I was surprised that it did not compile:

public class Test { public static int test1() { int a; try { a = 1; return a; // this is fine } finally { return a; // uninitialized value error here } } public static void main(String[] args) { int a = test1(); } } 

The most obvious code path (the only one I see) is to execute a = 1, "try" to return (first time), and then execute finally, which actually returns a. However, javac complains that "a" may not have been initialized:

  Test.java:8: variable a might not have been initialized  
         return a;  
                ^  

The only thing I can think of that can cause / resolve another code path is that after the start of the attempt, an incomprehensible exception occurred at runtime, but before the value 1 is set to a-something similar to OutOfMemoryError or a StackOverflowException exception, but I can't think of a single case where this could happen at this point in the code.

Could someone more familiar with the specifics of the Java standard shed some light on this? Is it just a case where the compiler is conservative and therefore refuses to compile what would otherwise be the correct code, or is something weirder going on here?

+6
java variables initialization finally
source share
7 answers

It would seem intuitively that an exception may occur on line a = 1, but a JVM error may occur. Thus, leaving the variable uninitialized. So a compiler error makes sense. This is the incomprehensible runtime error you were talking about. Nevertheless, I would say that OutOfMemoryError is far from obscurity and, at least, developers will think about it. Also, remember that the state that OutOfMemoryError sets can happen on another thread, and one action that pushes the amount of heap memory used outside the limit is to assign the variable a.

In any case, since you are looking at a compiler project, I also assume that you already know how silly it is to return values ​​to a finally block.

+10
source share

The Java language specification requires that a variable be assigned before it is used. JLS defines specific rules for rules defined as "Specific Assignment". All Java compilers must adhere to them.

JLS 16.2.15 :

V is definitely assigned before the finally block if V is definitely assigned before the try statement.

In other words, when considering a finally statement, try and catch try-catch-finally not considered in the assignments of try-catch-finally .

Needless to say, this specification is very conservative here, but they would prefer the specification to be simple, while a bit limited (they believe that the rules are already complicated) than to be soft, but hard to understand and reason.

Compilers must follow these Specific Purpose rules, so all compilers throw the same errors. Compilers are not allowed to perform any further analysis than JLS indicates suppression of any errors.

+7
source share

I believe this is only explained by the semantics of the try-catch-finally relationships. From the Java language specification :

If the execution of the try block completes normally, then finally the block is executed ...

If the execution of the try block suddenly terminates due to a throw of the value V ...

If the execution of the try block suddenly terminates for any other R mind, then the finally block is executed ...

The latter case seems to be the most relevant. It looks like the finally block should be executed correctly if the try block terminates abruptly for ANY reason. Obviously, if the try block completed before the assignment, the finally block will not be valid. Although, as you said, this is not particularly likely.

+3
source share

Probably, javac should make the assumption that an exception can occur at any point in the try block even during the assignment, and therefore, finally, it is possible to return an uninitialized variable. Theoretically, he could conduct a detailed analysis and find that in all paths through the try 'a' block it will always be successfully initialized, but this work will hardly be received.

Now, if someone can simply specify the appropriate section in the Java Language Specification ...

+2
source share

compiler errors occur in conditional blocks if the compiler is not sure that the next (subsequent) operator will work as

 int i=5;int d; if(i<10) {system.out.println(d);} 

compiler errors will not occur if a conditional statement is defined and invalid code is not reached, for example

 int i; 

if(true){}

 else {System.out.println(d);} 

and compiler errors will occur if the conditional statement definitely takes place and dubious code is reached, for example

 int i; if(true) {System.out.println(d);} else{} 

since try blocks are under this, they follow the same rules.

+2
source share

I think the Java Compiler assumes the worst case - there is no guarantee that anything in the try block even runs for some reason. Thus, his complaint is valid. The variable may not have been initialized.

+1
source share

The compiler here is simply conservative.

0
source share

All Articles