Fundamentals 17 min read

Mastering Java Enums: From Basics to Advanced Design Patterns

This article explains what Java enums are, why they are useful, how to define simple and custom enum types, compare them safely, use them in switch statements, enrich them with fields, methods and constructors, and apply them in advanced scenarios such as EnumSet, EnumMap, Singleton and Strategy patterns, as well as Java 8 stream APIs and JSON serialization.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Mastering Java Enums: From Basics to Advanced Design Patterns

Overview

In this article we explore what Java enums are, the problems they solve, and how to use them to implement several design patterns.

Simple Enum Example

Enum was introduced in Java 5 as a special kind of class that always extends java.lang.Enum. The following example defines a simple enum for pizza order status with three constants:

package shuang.kou.enumdemo.enumtest;

public enum PizzaStatus {
    ORDERED,
    READY,
    DELIVERED;
}

Using this enum avoids the need for separate constant definitions and groups related values together.

System.out.println(PizzaStatus.ORDERED.name()); // ORDERED
System.out.println(PizzaStatus.ORDERED); // ORDERED
System.out.println(PizzaStatus.ORDERED.name().getClass()); // class java.lang.String
System.out.println(PizzaStatus.ORDERED.getClass()); // class shuang.kou.enumdemo.enumtest.PizzaStatus

Custom Enum Methods

We can add additional API methods to an enum to make it more powerful. The following class shows a pizza with a nested enum and a method that checks whether the pizza is deliverable:

public class Pizza {
    private PizzaStatus status;
    public enum PizzaStatus {
        ORDERED,
        READY,
        DELIVERED;
    }

    public boolean isDeliverable() {
        if (getStatus() == PizzaStatus.READY) {
            return true;
        }
        return false;
    }
    // getters and setters omitted
}

Comparing Enums with ==

Because each enum constant is a singleton, the == operator can be used safely for both compile‑time and run‑time checks.

if (testPz.getStatus() == Pizza.PizzaStatus.DELIVERED) {
    // safe comparison
}

Using equals can throw a NullPointerException when the left‑hand side is null, while == does not.

Enum in switch Statements

public int getDeliveryTimeInDays() {
    switch (status) {
        case ORDERED:   return 5;
        case READY:     return 2;
        case DELIVERED: return 0;
    }
    return 0;
}

Enum Fields, Methods, and Constructors

Enums can declare fields, methods, and constructors to store additional data. The example below adds a delivery‑time field and overrides methods for each constant:

public class Pizza {
    private PizzaStatus status;
    public enum PizzaStatus {
        ORDERED(5) {
            @Override public boolean isOrdered() { return true; }
        },
        READY(2) {
            @Override public boolean isReady() { return true; }
        },
        DELIVERED(0) {
            @Override public boolean isDelivered() { return true; }
        };
        private int timeToDelivery;
        public boolean isOrdered() { return false; }
        public boolean isReady() { return false; }
        public boolean isDelivered() { return false; }
        public int getTimeToDelivery() { return timeToDelivery; }
        PizzaStatus(int timeToDelivery) { this.timeToDelivery = timeToDelivery; }
    }
    public boolean isDeliverable() { return this.status.isReady(); }
    public void printTimeToDeliver() {
        System.out.println("Time to delivery is " + getStatus().getTimeToDelivery());
    }
    // getters and setters omitted
}

A unit test demonstrates the behavior:

@Test
public void givenPizaOrder_whenReady_thenDeliverable() {
    Pizza testPz = new Pizza();
    testPz.setStatus(Pizza.PizzaStatus.READY);
    assertTrue(testPz.isDeliverable());
}

EnumSet and EnumMap

EnumSet

is a highly efficient Set implementation for enum types, using an internal bit vector. It provides a type‑safe alternative to int flag patterns.

private static EnumSet<PizzaStatus> undeliveredPizzaStatuses =
        EnumSet.of(PizzaStatus.ORDERED, PizzaStatus.READY);

Typical bulk operations such as containsAll or removeAll are fast, and iteration can be done via EnumSet.iterator() or EnumSet.values().

@Test
public void givenPizaOrders_whenRetrievingUnDeliveredPzs_thenCorrectlyRetrieved() {
    List<Pizza> pzList = new ArrayList<>();
    // add pizzas with various statuses
    List<Pizza> undeliveredPzs = Pizza.getAllUndeliveredPizzas(pzList);
    assertTrue(undeliveredPzs.size() == 3);
}
EnumMap

is a compact map implementation that uses an array internally, mapping enum constants to values.

public static EnumMap<PizzaStatus, List<Pizza>> groupPizzaByStatus(List<Pizza> pizzaList) {
    EnumMap<PizzaStatus, List<Pizza>> pzByStatus =
        new EnumMap<>(PizzaStatus.class);
    for (Pizza pz : pizzaList) {
        PizzaStatus status = pz.getStatus();
        pzByStatus.computeIfAbsent(status, k -> new ArrayList<>()).add(pz);
    }
    return pzByStatus;
}

A test verifies correct grouping:

@Test
public void givenPizaOrders_whenGroupByStatusCalled_thenCorrectlyGrouped() {
    List<Pizza> pzList = new ArrayList<>();
    // add pizzas with various statuses
    EnumMap<PizzaStatus, List<Pizza>> map = Pizza.groupPizzaByStatus(pzList);
    assertTrue(map.get(Pizza.PizzaStatus.DELIVERED).size() == 1);
    assertTrue(map.get(Pizza.PizzaStatus.ORDERED).size() == 2);
    assertTrue(map.get(Pizza.PizzaStatus.READY).size() == 1);
}

Design Patterns with Enums

Singleton Pattern

Using a single‑element enum is the simplest way to implement a thread‑safe singleton with built‑in serialization support.

public enum PizzaDeliverySystemConfiguration {
    INSTANCE;
    private PizzaDeliveryStrategy deliveryStrategy = PizzaDeliveryStrategy.NORMAL;
    public static PizzaDeliverySystemConfiguration getInstance() { return INSTANCE; }
    public PizzaDeliveryStrategy getDeliveryStrategy() { return deliveryStrategy; }
}

Strategy Pattern

Enum constants can each provide a different implementation of a common method, making it easy to add new strategies.

public enum PizzaDeliveryStrategy {
    EXPRESS {
        @Override public void deliver(Pizza pz) {
            System.out.println("Pizza will be delivered in express mode");
        }
    },
    NORMAL {
        @Override public void deliver(Pizza pz) {
            System.out.println("Pizza will be delivered in normal mode");
        }
    };
    public abstract void deliver(Pizza pz);
}

The Pizza class can delegate delivery to the configured strategy:

public void deliver() {
    if (isDeliverable()) {
        PizzaDeliverySystemConfiguration.getInstance()
            .getDeliveryStrategy().deliver(this);
        setStatus(PizzaStatus.DELIVERED);
    }
}

Java 8 and Enums

Using streams and lambda expressions simplifies operations on collections of enums:

public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
    return input.stream()
        .filter(s -> !undeliveredPizzaStatuses.contains(s.getStatus()))
        .collect(Collectors.toList());
}

public static EnumMap<PizzaStatus, List<Pizza>> groupPizzaByStatus(List<Pizza> pzList) {
    return pzList.stream().collect(
        Collectors.groupingBy(Pizza::getStatus,
            () -> new EnumMap<>(PizzaStatus.class),
            Collectors.toList()));
}

Enum JSON Representation

Jackson can serialize an enum as a JSON object by using @JsonFormat(shape = JsonFormat.Shape.OBJECT) and annotating fields.

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum PizzaStatus {
    ORDERED(5) { @Override public boolean isOrdered() { return true; } },
    READY(2)   { @Override public boolean isReady()   { return true; } },
    DELIVERED(0){ @Override public boolean isDelivered(){ return true; } };
    private int timeToDelivery;
    public int getTimeToDelivery() { return timeToDelivery; }
    private PizzaStatus(int timeToDelivery) { this.timeToDelivery = timeToDelivery; }
    // other methods omitted
}

Serializing a Pizza instance yields JSON such as:

{
  "status": {
    "timeToDelivery": 2,
    "ready": true,
    "ordered": false,
    "delivered": false
  },
  "deliverable": true
}

Summary

The article covered Java enums from basic definitions to advanced uses, demonstrating how enums improve type safety, enable rich behavior, and serve as building blocks for patterns like Singleton and Strategy, as well as how they integrate with Java 8 streams and JSON serialization.

Supplement

Enums can also hold additional data for use cases such as SMS verification codes. The following enum shows how to store a numeric code and a description:

public enum PinType {
    REGISTER(100000, "注册使用"),
    FORGET_PASSWORD(100001, "忘记密码使用"),
    UPDATE_PHONE_NUMBER(100002, "更新手机号码使用");
    private final int code;
    private final String message;
    PinType(int code, String message) { this.code = code; this.message = message; }
    public int getCode() { return code; }
    public String getMessage() { return message; }
    @Override public String toString() {
        return "PinType{code=" + code + ", message='" + message + "'}";
    }
}

Usage example:

System.out.println(PinType.FORGET_PASSWORD.getCode());
System.out.println(PinType.FORGET_PASSWORD.getMessage());
System.out.println(PinType.FORGET_PASSWORD);
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSingletonstrategyEnumsEnumMapEnumSet
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.