Java forcing default return statement from method with enum switch with all enum values covered

nibsa :

I have the following example situation:

public void shouldReturnStringForEnum() {
    MessageType myType = getType();
    System.out.println(getMessageForType(myType));
}

String getMessageForType(MessageType myType) {
    switch(myType) {
        case error:
            return "Error type";
        case warning:
            return "Warning type";
        case info:
            return "Info type";
    }
} // <= error: missing return statement

MessageType getType() {
    Random random = new Random();
    return MessageType.values()[random.nextInt(3)];
}

enum MessageType {error, warning, info }

I can't figure out what is the possibility to return from method getMessageForType in other way than from the body of switch statement. I was thinking about:

  • de-serialization from I/O data - but then java.lang.IllegalArgumentException: No enum constant happen long before call to getMessageForType
  • possible null method parameter - but then it will fail on switch(myType) evaluation with java.lang.NullPointerException

Forcing a default return statement is uncomfortable in such situations, because I don't know what to return here. Throwing an exception in such case also has no sense here. What is the design decision behind such behaviour?

Please help, what am I missing here?

Gray -- SO stop being evil :

Java forcing default return statement from method with enum switch with all enum values covered... What is the design decision behind such behaviour?

This is a very important (and correct) decision made by the language. Even though your current code handles all of the current values of the enum, that doesn't mean that the enum class might change long after your code is compiled. You might upgrade a 3rd party library and it might add another enum value causing your code to be invalid at runtime without the default.

Even if you control the enum code that doesn't mean that another developer (or future you) might add another value to the enum and fail to update the switch statement. Writing code that is forward compatible in this manner is generally a best practice and in this case critical for the language to force the behavior.

I don't know what to return here.

The question then comes down to whether to throw an exception or not. How to handle the invalid enum value or other exceptional conditions is something that we as programmers struggle with daily. In this case, you need to ask yourself what you want to happen? Is it an annoyance that shouldn't throw or is it a more critical error? Should the caller handle the exception or is a RuntimeException ok? These are questions you need to answer within the context of your application.

Lastly, I don't know about you, but most programmers I know cut&paste a lot of code. Although this enum may never be expanded, future enums will be expanded and making a good decision may benefit from appropriately handling this case.

Forcing a default return statement is uncomfortable in such situations...

"Unknown type" might be a good choice.

case ...:
     return ...;
default:
     // here in case someone updates the enum and forgets to update this code
     return "Unknown type";

Throwing an exception in such case also has no sense here.

This depends a bit on how big a deal returning the default "unknown" string is. In the case that there is a new enum with a missing case entry, would you want it to throw an exception or not?

For exceptions, you might want to use:

case ...:
     return ...;
default:
     throw new IllegalStateException("unknown enum type found for" + mType);

or maybe IllegalArgumentException.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=91304&siteId=1