Skip to the content.
blog talks media about resources

I won’t let Java confuse you #4: unreachable statements

Do you think Java consistently rejects all unreachable code? Well…

Welcome back to the Java-unconfusing series! Usually here we take a look at the pieces of code which may look really innocent, but not work as we expect. Or not compile at all. It’s good to dive into the reasons why it is a certain way, so we can learn more about Java ideology and design decisions. Let’s get unconfused together!

Let’s talk about unreachable statements

There are a number of different use-cases when the code is considered unreachable. The compiler doesn’t accept this code. Examples include statements that follow break or return, or infinite while(true) loops, for example. We have all seen these.

Let’s take a look at this particular example:

int a = 0;
while (false) {
    a = 10;
}

The compiler tells us that the loop condition is always false, and that makes the loop body unreachable. Makes sense that it doesn’t compile.

What about the following example?

int a = 0;
if (false) {
    a = 10;
}

The condition is always false, which means that the body can never be executed. However, this piece of code is accepted by the compiler! Technically, the Java compiler doesn’t even consider it ‘unreachable’.

Why is it so?

This choice has been made consciously. When the condition is a constant false value, the compiler doesn’t add the contents of the entire conditional block to the resulting set of the bytecode instructions. This allows developers to define flags such as:

static final boolean FEATURE = false;

And then use it in a condition.

Later on, it’s easy to change the value of the FEATURE flag to true, but there’s one important detail to it. If the flag itself and the conditional block are located in different classes, it’s important to recompile the class containing the condition, since the whole new set of instructions might be added to the bytecode.

When is it so?

Coming back to our while (false) example, such behaviour is only happening when the condition is a constant false value.

So, this would work without any issue:

int a = 0;
int b = 10;
while (b + b < 10) {
    a = 1;
}

While this wouldn’t compile:

int a = 0;
final int b = 10;
while (b + b < 10) {
    a = 1;
}

The reason is that the compiler is performing optimisation called ‘constant folding’. All known (constant) values can be used in order to pre-calculate anything where possible. If the values are constant, the assumptions can be safely made, but not otherwise.

So, in the example above, the compiler knows that our actual condition is 10 + 10 < 10, and it is false, and it can’t be changed from anywhere else in the code. So it is safe to conclude that the code is invalid.

Crazy thoughts

Curious minds might wonder: if if (false) {} block contents are not placed into the bytecode at all, does it mean that the compilation of that block is skipped entirely? So any nonsense inside that block would not result in a compile error? The answer is no. The compiler still diligently does its work and reports any compile errors within that block.

Hope this was educative and fun! Here are the related docs.

If you liked this little post, take a look at the previous posts from the series:

back to blog
Hits