5

The compiler claims that a return statement is missing at the end of MyClass.parse(). Here is the code:

package de.hs_rm.safelyovertaken.ble;

import android.support.annotation.NonNull;

import java.util.Arrays;

class MyClass {

    @NonNull
    static MyClass parse(byte[] encoded) throws MyParseException {

        MyEnum myEnum = MyEnum.parse(Arrays.copyOfRange(encoded, 0, 2));

        switch (myEnum) {
            case A:
                return new MyClassA();

            case B:
                return new MyClassB();

            case C:
                return new MyClassC();
        }

        // compile error: "Missing return statement"

//        return null; // should never be reached
//        throw new AssertionError("Should never be reached");
    }
}

enum MyEnum {
    A, B, C;

    @NonNull
    static MyEnum parse(byte[] encoded) throws MyParseException {

        MyEnum result = null;

        // parse logic here

        if (result == null) {
            throw new MyParseException();
        }

        return result;
    }
}

class MyParseException extends Exception {
}

class MyClassA extends MyClass {
}

class MyClassB extends MyClass {
}

class MyClassC extends MyClass {
}

Is the compiler right? (Android Studio)

If so, under what circumstances could the end of the method be reached? I think myEnum cannot be null and all enum are covered in the switch statement where in any case a return statement will leave the method. myEnum cannot be null because the @NonNull method MyEnum.parse() throws an exception if the result is null.

If not, would you mark the (hopefully) unreachable end of the method with return null // should never be reached or throw an AssertionError?

Tobias Uhmann
  • 2,757
  • 2
  • 25
  • 35
  • '`myEnum` cannot be `null` because the `@NonNull` method `MyEnum.parse()` throws an exception if the result is `null`' - the compiler doesn't know that – crizzis May 02 '18 at 20:14

1 Answers1

8

Is the compiler right?

Yes, because it doesn't verify enum coverage at compile time. Say the enum lived in another binary and it was updated with a new constant. What would the method return?

myEnum cannot be null because the @NonNull method MyEnum.parse() throws an exception if the result is null.

The compiler's not smart enough to figure that out (though your IDE might be). But it's a moot point because switching on null would result in a NPE.

If not, would you mark the (hopefully) unreachable end of the method with return null // should never be reached or throw an AssertionError?

Throwing an AssertionError is pretty conventional. Alternatively, consider embedding conditional logic in the enum constants instead of using a switch.

shmosel
  • 49,289
  • 6
  • 73
  • 138
  • I thought checking enum coverage in switch statements was an advantage of enums over constants. But yeah.. as enum values are stored in the .class file that uses them the scenario you described should make the check technically impossible. – Tobias Uhmann May 02 '18 at 20:26
  • TBH I never followed the logic of 'say the enum lived in another jar and it was updated with a new constant'. I know it's about breaking vs non-breaking change but... if my code was robust enough to handle enum cases that weren't even there at the time of writing, then I guess all I would **ever** need would be the `default` clause. Embedding conditional logic in the enum constants is just so much better than the switch clause – crizzis May 02 '18 at 20:40