Enums in Java
An enum is a class with a fixed set of instances, which makes an invalid value impossible rather than merely unlikely.
-
Java Basics
- Introduction to Java
- Setting Up Java and Writing Your First Program
- Variables, Data Types and Literals in Java
- Type Casting and Type Conversion in Java
- Operators and Expressions in Java
- Input and Output in Java
- Comments, Keywords and Naming Conventions in Java
- Control Flow in Java: if, else and switch
- Loops in Java: for, while and do-while
- Methods
- Arrays and Strings
-
OOP
- Classes and Objects in Java
- Constructors in Java
- The this Keyword in Java
- The static Keyword in Java
- Encapsulation in Java
- Access Modifiers in Java
- Inheritance in Java
- Method Overriding and super in Java
- Polymorphism in Java
- Abstraction, Abstract Classes and Interfaces in Java
- Composition, Aggregation and Association in Java
- The Object Lifecycle in Java
- Core Java
- Exception Handling
-
Collections
- The Java Collections Framework
- List in Java: ArrayList, LinkedList, Vector and Stack
- Set in Java: HashSet, LinkedHashSet and TreeSet
- Map in Java: HashMap, LinkedHashMap and TreeMap
- How HashMap Works Internally in Java
- Queue and Deque in Java: ArrayDeque and PriorityQueue
- Iterators in Java
- Comparable and Comparator in Java
- Collections Utilities and Choosing the Right Collection
- Generics
- Java 8+
- Stream API
- Date and Time
- File and I/O
-
Multithreading
- Threads in Java: Processes, Runnable and Thread
- Thread Lifecycle in Java
- Synchronization in Java: synchronized and volatile
- Locks and Atomic Classes in Java
- Race Conditions and Deadlocks in Java
- The Executor Framework and Thread Pools in Java
- Future and CompletableFuture in Java
- Concurrent Collections in Java
- The Java Memory Model
- JVM and Memory
- Advanced Java
- Networking
- JDBC
- Testing
Definition
An enum declares a type whose instances are a fixed, named set created once by the JVM. Each constant is a singleton, and no other instance can ever exist.
public enum Status {
DRAFT, PUBLISHED, ARCHIVED
}Why enums exist
// Before enums: nothing prevents an invalid value
public static final int STATUS_DRAFT = 0;
public static final int STATUS_PUBLISHED = 1;
setStatus(47); // compiles happily, and is meaninglesssetStatus(Status.PUBLISHED); // the only values that exist are the valid ones- Invalid values become a compile error.
- The name appears in logs and debuggers rather than a number.
- A
switchover an enum can be checked for exhaustiveness. - Behaviour can live on the constant itself.
Built in members
Status s = Status.PUBLISHED;
System.out.println(s.name()); // PUBLISHED
System.out.println(s.ordinal()); // 1, the declaration position
System.out.println(s); // PUBLISHED, toString defaults to the name
Status parsed = Status.valueOf("DRAFT"); // throws if the name is unknown
for (Status value : Status.values()) {
System.out.println(value);
}Never persistordinal(). Reordering the constants silently changes every stored value. Persistname(), or an explicit code field you control.
Fields, constructors and methods
public enum Plan {
FREE("Free", 0),
STANDARD("Standard", 499),
PREMIUM("Premium", 999);
private final String label;
private final int monthlyPrice;
Plan(String label, int monthlyPrice) { // implicitly private
this.label = label;
this.monthlyPrice = monthlyPrice;
}
public String label() {
return label;
}
public int annualPrice() {
return monthlyPrice * 12;
}
public boolean isPaid() {
return monthlyPrice > 0;
}
}System.out.println(Plan.STANDARD.annualPrice()); // 5988The constructor runs once per constant, when the enum class is initialised. It cannot be public, because no further instances may be created.
Constant specific behaviour
public enum Operation {
ADD {
@Override public double apply(double a, double b) { return a + b; }
},
SUBTRACT {
@Override public double apply(double a, double b) { return a - b; }
},
MULTIPLY {
@Override public double apply(double a, double b) { return a * b; }
};
public abstract double apply(double a, double b);
}System.out.println(Operation.MULTIPLY.apply(6, 7)); // 42.0Each constant supplies its own implementation. Adding a new operation forces you to write its behaviour, which a switch would not.
Enums in switch
String message = switch (status) {
case DRAFT -> "Not visible yet";
case PUBLISHED -> "Live";
case ARCHIVED -> "Hidden";
};No default is needed, and none should be added. Without it, adding a fourth constant makes this switch fail to compile, which is exactly the reminder you want. Note that the constants are written unqualified inside case.
EnumSet and EnumMap
EnumSet<Status> visible = EnumSet.of(Status.PUBLISHED, Status.ARCHIVED);
EnumSet<Status> hidden = EnumSet.complementOf(visible);
EnumMap<Status, Integer> counts = new EnumMap<>(Status.class);
counts.put(Status.DRAFT, 12);These specialised implementations are backed by bit vectors and arrays indexed by ordinal. They are considerably faster and smaller than HashSet and HashMap for enum keys, and they iterate in declaration order.
Enums can implement interfaces
public enum Currency implements Comparable<Currency> {
INR, USD, EUR
}An enum implicitly extends java.lang.Enum, so it cannot extend another class, but it may implement any number of interfaces.
The singleton idiom
public enum Registry {
INSTANCE;
private final Map<String, String> values = new ConcurrentHashMap<>();
public void put(String key, String value) {
values.put(key, value);
}
}A single constant enum is the most robust singleton in Java: the JVM guarantees one instance, and it is safe against reflection and serialisation attacks that defeat a private constructor.
Common mistakes
- Storing or transmitting
ordinal(). - Adding a
defaultbranch to an enum switch, which silences the compiler check. - Calling
valueOfwith unvalidated input and not handlingIllegalArgumentException. - Comparing with
equalswhere==is safe, correct and null tolerant. - Putting mutable state on an enum constant, which is effectively global mutable state.
Best practices
- Use an enum wherever a value comes from a small fixed set.
- Compare with
==. - Give constants an explicit code field when the value is persisted.
- Prefer constant specific methods over a
switchon the enum inside the enum itself. - Use
EnumSetandEnumMapfor enum keyed collections.
Practice
- Write a
Dayenum with a method reporting whether it is a working day. - Why is
Plan(String, int)not allowed to be public? - Add a constant to an enum used in a switch expression with no
defaultand observe the compile error. - Implement a
Directionenum where each constant returns its opposite. - Explain why a single constant enum is a safer singleton than a class with a private constructor.
Conclusion
An enum turns a set of valid values into a type. Give constants fields and behaviour, compare with ==, avoid ordinal in stored data, and let the compiler check your switches.