Enum Values in Exhaustive switch Expressions
A switch expression is always exhaustive—that is, the cases defined in the switch expression must cover all values of the selector expression type or the code will not compile (§4.2, p. 160).
The switch expression below at (1) is exhaustive, as all values of the enum type Day are covered by the two switch rules at (2) and (3). Deleting any one or both of these switch rules will result in a compile-time error.
Day day = Day.MONDAY; // See Example 5.26, p. 295, for enum type Day.
String typeOfDay = switch (day) { // (1)
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> “Weekday”; // (2)
case SATURDAY, SUNDAY -> “Weekend”; // (3)
};
The switch expression below at (4) is also exhaustive, as all values of the enum type Day are collectively covered by the case label at (5) and the default label at (6). Deleting the case label at (5) does not result in a compile-time error, as the default label will then cover all values of the selector expression—but it may result in a wrong value being returned by the switch expression. However, deleting the default label at (6) will result in a compile-time error, as the case label at (5) only covers a subset of the values for the Day enum type. Compile-time checking of exhaustiveness of a switch expression whose switch rules are defined by the arrow notation results in robust and secure code.
typeOfDay = switch (day) { // (4)
case SATURDAY, SUNDAY -> “Weekend”; // (5)
default -> “Weekday”; // (6)
}
Declaring Type-Safe Enums, Revisited
We have seen declarations of enum types as top-level types, but they can also be nested as static member and static local types (§9.1, p. 491). Although nested enum types are implicitly static, they can be declared with the keyword static. The following skeletal code shows the two enum types Day and Meal declared as static member types in the class MealPrices:
public class MealPrices {
public enum Day { /* … */ } // Static member
public static enum Meal { /* … */ } // Static member
public static void main(String[] args) { /* … */ } // Static method
}
An enum type cannot be explicitly extended using the extends clause. An enum type is implicitly final, unless it contains constant-specific class bodies. If it declares constant-specific class bodies, it is implicitly extended. No matter what, it cannot be explicitly declared final.
An enum class is either implicitly final if its declaration contains no enum constants that have a class body, or implicitly sealed if its declaration contains at least one enum constant that has a class body. Since an enum type can be either implicitly final or implicitly sealed, it can implement a sealed interface—in which case, it must be specified in the permits clause of the sealed interface (p. 311).
An enum type cannot be declared abstract, regardless of whether each abstract method is overridden in the constant-specific class body of every enum constant.
Like a class, an enum can implement interfaces.
public interface ITimeInfo {
public int getHour();
public int getMins();
}
public enum Meal implements ITimeInfo {
// …
@Override public int getHour() { return this.hh; }
@Override public int getMins() { return this.mm; }
// …
}
The Java Collections Framework provides a special-purpose set implementation (java.util.EnumSet) and a special-purpose map implementation (java.util.EnumMap) for use with enum types. These implementations provide better performance for enum types than their general-purpose counterparts, and are worth checking out.
Leave a Reply