What is the usage of default when the switch is for an enum?
Suppose I have an enum Color
with 2 possible values: RED
and BLUE
:
public enum Color {
RED,
BLUE
}
Now suppose I have a switch statement for this enum where I have code for both possible values:
Color color = getColor(); // a method which returns a value of enum "Color"
switch (color) {
case RED:
...
break;
case BLUE:
...
break;
default:
break;
}
Since I have code block for both possible values of the enum, what is the usage of default
in the above code?
Should I throw an exception if the code somehow reaches the default
block like this?
Color color = getColor(); // a method which returns a value of enum "Color"
switch (color) {
case RED:
...
break;
case BLUE:
...
break;
default:
throw new IllegalArgumentException("This should not have happened");
}
It is good practice to throw an Exception as you have shown in the second example. You improve the maintainability of your code by failing fast.
In this case it would mean if you later (perhaps years later) add an enum value and it reaches the switch statement you will immediately discover the error.
If the default value were not set, the code would perhaps run through even with the new enum value and could possibly have undesired behavior.
The other answers are correct in saying that you should implement a default
branch that throws an exception, in case a new value gets added to your enum in the future. However, I would go one step further and question why you're even using a switch
statement in the first place.
Unlike languages like C++ and C#, Java represents Enum values as actual objects, which means that you can leverage object-oriented programming. Let's say that the purpose of your method is to provide an RGB value for each color:
switch (color)
case RED:
return "#ff0000";
...
Well, arguably, if you want each color to have an RGB value, you should include that as part of its description:
public enum Color
{
RED("#FF0000"),
BLUE("#0000FF");
String rgb;
public Color(String rgb) {
this.rgb = rgb;
}
public getRgb() { return this.rgb; }
}
That way, if you add a new color later, you're pretty much forced to provide an RGB value. It's even more fail-fast than the other approach, because you'll fail at compile-time rather than run-time.
Note that you can do even more complicated things if you need to, including having each color provide its own custom implementation of an abstract method. Enums in Java are really powerful and object-oriented, and in most cases I've found I can avoid needing to switch
on them in the first place.
Compile time completeness of the switch cases doesn't guarantee runtime completenes.
Class with a switch statement compiled against an older version of enum may be executed with a newer enum version (with more values). That's a common case with library dependencies.
For reasons like these, the compiler considers the switch
without default
case incomplete.
In small programs, there is no practical use for that, but think of a complex system that speards among large number of files and developers - if you define the enum
in one file and use it in another one, and later on someone adds a value to the enum
without updating the switch
statement, you'll find it very useful...
If you've covered all of the possibilities with your various cases
and the default
cannot happen, this is the classic use case for assertions:
Color color = getColor(); // a method which returns a value of enum "Color"
switch (color) {
case RED:
// ...
break;
case BLUE:
// ...
break;
default:
assert false; // This cannot happen
// or:
throw new AssertionError("Invalid Colors enum");
}