Java › Enums

How would you use an EnumMap combined with a switch expression to implement a state machine, and what compile-time safety benefits does an exhaustive switch over an enum provide?

Advanced

Answer

Modeling a state machine's states as an enum, with transitions defined either via an EnumMap<State, Map<Event, State>> lookup table or a switch expression over the current state and incoming event, gives you a structure the compiler can help verify is exhaustive (a switch expression over an enum, especially without a default branch in modern Java, forces you to explicitly handle every enum constant, immediately flagging at compile time if a new state is added but its transition handling was forgotten) -- this compile-time exhaustiveness checking is a meaningful safety benefit over an equivalent if/else chain or a Map-based lookup that would fail only at runtime (or silently do nothing) if a state was missed.
enum State { IDLE, RUNNING, PAUSED, STOPPED }
enum Event { START, PAUSE, RESUME, STOP }

State transition(State current, Event event) {
    return switch (current) {
        case IDLE -> event == Event.START ? State.RUNNING : current;
        case RUNNING -> switch (event) {
            case PAUSE -> State.PAUSED;
            case STOP -> State.STOPPED;
            default -> current;
        };
        case PAUSED -> event == Event.RESUME ? State.RUNNING : current;
        case STOPPED -> current;
        // Compiler ERROR if a new State constant is added but not handled here (no default case)
    };
}
Real-world example An order-processing state machine (PENDING, PAID, SHIPPED, DELIVERED, CANCELLED) implemented with an exhaustive switch expression immediately produces a compile error when a new CANCELLED_REFUNDED state is added to the enum but its transition logic is forgotten in the switch, catching an incomplete state machine implementation at build time rather than allowing a runtime bug to reach production.

Common follow-ups: What happens if you DO include a default case in an otherwise-exhaustive enum switch -- does it lose the exhaustiveness-checking benefit?;How would you implement this same state machine using an EnumMap-based transition table instead of a switch expression, and what are the trade-offs?