Question

boolean method(int value) {
    switch(value) {
    case 0:
        return false;
    case 1:
        return true;
    default:
        Assert.fail("Unhandled value.");
    }
}

This fails compilation with the error "Method must return a result" even though Assert.fail() does nothing but throw an AssertionError. If I throw an AssertionError myself instead of calling Assert.fail() it compiles.

Was it helpful?

Solution

The compiler has no way of knowing that Assert.fail will always throw an exception, unless it were to delve into the bytecode of that method and do some sort of static analysis on it (and once you start this sort of thing then where do you stop?). The Java Language Specification states (section 8.4.7)

If a method is declared to have a return type, then a compile-time error occurs if the body of the method can complete normally (§14.1).

where "can complete normally" in your example boils down to (section 14.21)

A non-empty block that is not a switch block can complete normally iff the last statement in it can complete normally.

The last statement in your method is a switch statement:

A switch statement can complete normally iff at least one of the following is true:

[...]

  • The last statement in the switch block can complete normally.

The last statement in the switch is an expression statement (a method call)

An expression statement can complete normally iff it is reachable.

i.e. the spec specifically states that the compiler shouldn't look inside any method calls, and any method call expression must be considered to be one that can complete normally.

The same section also defines that

A break, continue, return, or throw statement cannot complete normally.

So to keep the compiler happy you'll need to add a return or throw to the end of the method

// will never be reached
throw new Error();

I'd personally go for a throw, with a comment explaining that something has gone very wrong if this line is ever reached...

OTHER TIPS

It is impossible for the compiler to know that Assert.fail() will always throw an exception so the compiler still requires a return statement (or an explicit throw as suggested by Ian Roberts). When you explicitly code the throw new AssertionError() the compiler knows for certain that the closing } of the method cannot be reached and a return is unrequired.

You must always have a return value or an exception for all code paths. The compile does not know that Assert.fail does not always throw an exception

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top