Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to ensure completeness in an enum switch at compile time?

I have several switch statements which test an enum. All enum values must be handled in the switch statements by a case statement. During code refactoring it can happen that the enum shrinks and grows. When the enum shrinks the compiler throws an error. But no error is thrown, if the the enum grows. The matching state gets forgotten and produces a run time error. I would like to move this error from run time to compile time. Theoretically it should be possible to detect the missing enum cases at compile time. Is there any way to achieve this?

The question exists already "How to detect a new value was added to an enum and is not handled in a switch" but it does not contain an answer only an Eclipse related work around.

like image 401
ceving Avatar asked May 28 '13 16:05

ceving


People also ask

Can you use a switch statement for enums?

We can use also use Enum keyword with Switch statement. We can use Enum in Switch case statement in Java like int primitive.

How do you use enums correctly?

You should always use enums when a variable (especially a method parameter) can only take one out of a small set of possible values. Examples would be things like type constants (contract status: “permanent”, “temp”, “apprentice”), or flags (“execute now”, “defer execution”).

Can you loop through enums?

Enums don't have methods for iteration, like forEach() or iterator(). Instead, we can use the array of the Enum values returned by the values() method.

Can you switch on enum Java?

You definitely can switch on enums.


3 Answers

In Effective Java, Joshua Bloch recommends creating an abstract method which would be implemented for each constant. For example:

enum Color {     RED   { public String getName() {return "Red";} },     GREEN { public String getName() {return "Green";} },     BLUE  { public String getName() {return "Blue";} };     public abstract String getName(); } 

This would function as a safer switch, forcing you to implement the method if you add a new constant.

EDIT: To clear up some confusion, here's the equivalent using a regular switch:

enum Color {     RED, GREEN, BLUE;     public String getName() {         switch(this) {             case RED:   return "Red";             case GREEN: return "Green";             case BLUE:  return "Blue";             default: return null;         }     } } 
like image 181
shmosel Avatar answered Oct 16 '22 21:10

shmosel


Another solution uses the functional approach. You just need to declare the enum class according with next template:

public enum Direction {

    UNKNOWN,
    FORWARD,
    BACKWARD;

    public interface SwitchResult {
        public void UNKNOWN();
        public void FORWARD();
        public void BACKWARD();
    }

    public void switchValue(SwitchResult result) {
        switch (this) {
            case UNKNOWN:
                result.UNKNOWN();
                break;
            case FORWARD:
                result.FORWARD();
                break;
            case BACKWARD:
                result.BACKWARD();
                break;
        }
    }
}

If you try to use this without one enumeration constant at least, you will get the compilation error:

getDirection().switchValue(new Direction.SwitchResult() {
    public void UNKNOWN() { /* */ }
    public void FORWARD() { /* */ }
    // public void BACKWARD() { /* */ } // <- Compilation error if missing
});
like image 44
Ilia Zlobin Avatar answered Oct 16 '22 19:10

Ilia Zlobin


I don't know about the standard Java compiler, but the Eclipse compiler can certainly be configured to warn about this. Go to Window->Preferences->Java->Compiler->Errors/Warnings/Enum type constant not covered on switch.

like image 27
Oliver Charlesworth Avatar answered Oct 16 '22 20:10

Oliver Charlesworth