The tricky Java compiler

jasy's picture

I think many of us have met the situation while compiling Java sources that the code was not compileable, although its small modification, which had the same semantic, provided a compileable code. This is annoying, especially when we want to carry out some automatic refactorings on our code.

In this blogpost I will collect some strange examples and I'll try to explain the reasons of the successful/unsuccessful compilation.
For this purpose I used the standard, but unfortunately it cannot provide any help in many of these cases. Sometimes the standard is much more strict than the compilers, which tries to slack the strictness of the standard, but unfortunately without a coherent manner. In the next sections I will emphasize some examples with the joint issues of the standard.
Everybody can decide whether the compilers follow it in the particular cases, or not.

Return statement

The following method is compileable:

Example 1:
public static int goo() {
    while(true) return 3;
}

while the followings are not:

Example 2:
public static int goo() {
    if(true) return 3;
}

Example 3:
public static int goo() {
    try{
        if(true) return 3;
    } catch(Exception e) {}
}

Example 4:
public static int goo() {
    try{
        while(true) return 3;
    } catch(Exception e) {}
}

This one is a little bit different, where there is no return statement although the method should return a String value:

Example 5:
String x(){
    for(;;);
}

The standard says:
"If a method is declared to have a return type, then every return statement (§14.17) in its body must have an Expression."
But this is no problem if there is no return statement. Our Example 5 suggests, but the standard declares, that it is possible for a method to have a declared return type and yet contains no return statements.

Example from the standard:
class DizzyDean {
int pitch() {
    throw new RuntimeException("90 mph?!"); }
}

But let's see the other four examples. We have to understand two concepts: "complete normally" and "abrupt completion". If all the steps are carried out as described in the standard, with no indication of abrupt completion, the statement is said to complete normally. However, certain events may prevent a statement from completing normally, such as the execution of a break, continue, return or throw statements. If such an event occurs, then execution of one or more statements may be terminated before all steps of their normal mode of execution have completed; such statements are said to complete abruptly. The terms complete normally and complete abruptly also apply to the evaluation of expressions (§15.6). The only reason an expression can complete abruptly is that an exception is thrown, because of either a throw with a given value (§14.18) or a run-time exception or error (§11, §15.6). A compile-time error occurs if the body of the method can complete normally (§14.1).

Let's see our Example 1. The condition is true, so the condition part completes normally, while the body of the while statement completes abruptly. So the whole while statement and the whole method is completed abruptly therefore this code is compileable.

In Example 2 the condition is true, and in this case the if statement completes normally if and only if the if-then statement completes normally. Although the statement completes abruptly we get the compile-time error. Needless to say that Example 1 and Example 2 are semantically equivalent methods.

In Example 3 and Example 4 we have to investigate whether a try statement completes normally or abruptly. Since the body of the try statements completes abruptly in both examples and these abrupt completitions come from return events (not from thrown exceptions), the try statements complete abruptly. And so it is not reasonable that the code is not compileable.

Next