AlgoInsight

Free lesson · Low Level Design Fundamentals

Enums

Easy4 min readlldoopdesign-patterns

Enums

An enum (enumeration) is a type whose values are a fixed, named set of constants - OrderStatus.PENDING, Day.MONDAY, Suit.HEARTS. The intent is to model a value that can only ever be one of a known, closed set, and to do so as a first-class type rather than as loose integers or strings. In Java specifically, an enum is far more than a list of names: it is a full class that can carry fields, methods, and per-constant behavior - which makes it one of the most underused tools for clean, type-safe object design.

This topic belongs in the object-oriented foundations alongside Classes and Objects, because an enum is a special kind of class. It connects forward to several later ideas: enums are the lightweight implementation of a small State machine (the State pattern, Module 17, and state-machine diagrams, Module 13.6); they're a core technique in type-driven design for making illegal values unrepresentable (Module 36); and they replace the "magic constant" smell that primitive obsession produces (Module 24).

In interviews, reaching for an enum instead of a string or int constant is a small, high-frequency signal of type-safety awareness. The deeper signal is knowing that a Java enum can hold behavior - turning a switch-on-status into polymorphism the language enforces.

The Problem It Solves

Representing a closed set with primitives invites invalid values and scattered logic:

class Order {
    private String status;   // "pending"? "PENDING"? "pendnig"? anything compiles
}
order.setStatus("shipped");
order.setStatus("banana");   // compiles fine - nonsense accepted
if (order.getStatus().equals("PENDING")) { ... }  // typo-prone string compares everywhere

A String (or an int code) status accepts any value, invites typos that the compiler can't catch, and scatters string comparisons throughout the code. There's no single place that says "these are the only legal statuses." An enum closes the set:

enum OrderStatus { PENDING, PAID, SHIPPED, DELIVERED, CANCELLED }

class Order {
    private OrderStatus status;     // only the five legal values can ever be assigned
}
order.setStatus(OrderStatus.SHIPPED);   // OrderStatus.BANANA does not compile

Now invalid statuses are impossible, comparisons are typo-proof (status == OrderStatus.PENDING), and the legal set is documented in one place.

Enums Can Carry Behavior

The feature most candidates miss: a Java enum is a class, so each constant can hold data and even override methods - letting you replace a switch with polymorphism.

graph TD
    A[Switch on an enum<br/>everywhere it's used] --> B[Logic for each value<br/>scattered across the codebase]
    C[Enum with fields & methods<br/>behavior lives on the constant] --> D[Add a new constant →<br/>define its behavior once, in one place]

    style C fill:#1e1b4b,color:#fff
A comparison of two ways to use an enum. In the first, code switches on the enum value everywhere it is used, so the logic for each value ends up scattered across the codebase, and adding a new value means hunting down every switch. In the second, the enum itself carries fields and methods, so the behavior for each value lives on the constant. Adding a new constant means defining its behavior once, in one place, and every user gets it automatically. The second approach turns a switch statement into polymorphism that the language enforces.
enum Operation {
    PLUS("+")  { public int apply(int a, int b) { return a + b; } },
    TIMES("*") { public int apply(int a, int b) { return a * b; } };

    private final String symbol;
    Operation(String symbol) { this.symbol = symbol; }
    public abstract int apply(int a, int b);   // each constant supplies its own
}

Here Operation.PLUS.apply(2,3) works without a single switch - the behavior is attached to the constant. Adding MINUS means adding one constant with its apply; nothing else changes (Open/Closed, Module 9). This is the idiomatic Java way to express a small, fixed family of behaviors.

Enums Beyond Constants

Enums also make excellent singletons (a single-constant enum is the simplest thread-safe singleton, Module 14.2), natural keys in EnumMap/EnumSet (compact and fast), and the backbone of small state machines where each constant knows its legal transitions. The guiding rule: whenever a value is conceptually "one of a fixed set," prefer an enum to a string or int - and when each member has distinct behavior, push that behavior onto the enum rather than switching on it elsewhere.

Why This Matters in Interviews

Using enums for statuses, types, and categories - rather than strings or int codes - is a baseline cleanliness signal. The standout move is behavior-carrying enums: when a design has per-type logic, modelling it as an enum with methods (or noting "I'd make each constant supply its own behavior so adding a type doesn't touch a switch") demonstrates real Java fluency and an Open/Closed instinct. Mentioning the single-constant-enum singleton is a classic, well-regarded detail.

Common Mistakes

Try It

Find a String or int constant in your code that represents one of a fixed set of values and convert it to an enum - then attempt to assign an invalid value and watch it fail to compile. Next, find a switch over that set and move each branch's logic onto the enum constants as methods. Adding a hypothetical new value should now require defining its behavior once, on the new constant, with no switch to hunt down. That refactor is the difference between an enum as a label and an enum as a design tool.

Back to Low Level Design Fundamentals