Skip to content

Java Enums

Updated 8 min read Aimerscrew

A Java enum (short for "enumeration") is a type with a fixed list of possible values, like the sizes on a menu, the days of the week or the stages of a food delivery. Instead of passing around fragile strings like "medium" or magic numbers like 2, you give each value a proper name that the compiler can check. In this lesson, you'll learn how to declare and use enums, the built-in methods every enum gets, how to switch on them, and how to give enum constants their own data and behavior.

🌍 Real-life example

A coffee shop offers exactly three cup sizes: small, medium and large. You can't order a "medum" or a "size 7". The menu is a closed list, and each size comes with its own volume and price. A Java enum models that kind of closed list perfectly, typos included: the compiler rejects them.

What is an enum in Java?

An enum is a special kind of class whose objects are a fixed set of named constants. You declare it with the enum keyword and list the constants, separated by commas. By convention, constant names are written in UPPER_SNAKE_CASE, like other Java constants.

public class TShirtShop {
    public static void main(String[] args) {
        Size chosen = Size.MEDIUM;
        System.out.println("You picked: " + chosen);

        if (chosen == Size.MEDIUM) {
            System.out.println("Medium is our best seller!");
        }

        // chosen = "Medium";   // compile error: a String is not a Size
    }
}

enum Size {
    SMALL, MEDIUM, LARGE, EXTRA_LARGE
}
You picked: MEDIUM
Medium is our best seller!

A few things to notice:

  • Size is a real type. A Size variable can only hold one of the four constants (or null).
  • You refer to a constant as Size.MEDIUM.
  • Printing an enum constant prints its name.
  • Each constant exists exactly once, so comparing with == is safe and correct. No equals() needed.

Why use an enum instead of strings or ints?

Before enums, programmers often wrote int size = 2; or String size = "MEDIUM";. Both let invalid values slip in:

ApproachExampleProblem
int codesint size = 2;What does 2 mean? Nothing stops size = 99.
StringsString size = "MEDUIM";Typos compile fine and fail later.
EnumSize size = Size.MEDIUM;Only valid values compile. Readable and type-safe.

Type-safe means the compiler checks that you only use values of the right type. A method with a Size parameter simply can't receive a misspelled string.

values(), ordinal(), name() and valueOf()

Every enum automatically gets some helpful methods:

  • values() returns an array of all constants, in the order you declared them.
  • ordinal() returns a constant's position, starting at 0.
  • name() returns the constant's name as a String, exactly as written in the code.
  • valueOf(String) turns a matching string back into the constant.
public class WeekPlanner {
    public static void main(String[] args) {
        for (Day d : Day.values()) {
            System.out.println(d.ordinal() + ": " + d.name());
        }

        Day fromText = Day.valueOf("FRIDAY");     // String -> enum constant
        System.out.println("Parsed: " + fromText);
        System.out.println("Days in a week: " + Day.values().length);
        System.out.println("Is SATURDAY after FRIDAY? " + (Day.SATURDAY.compareTo(Day.FRIDAY) > 0));
    }
}

enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
0: MONDAY
1: TUESDAY
2: WEDNESDAY
3: THURSDAY
4: FRIDAY
5: SATURDAY
6: SUNDAY
Parsed: FRIDAY
Days in a week: 7
Is SATURDAY after FRIDAY? true

Enums also have compareTo(), which compares by declaration order, just like compareTo() on strings compares alphabetically.

⚠️ Be careful

valueOf() is case-sensitive and must match a name exactly. Size.valueOf("HUGE") or Size.valueOf("medium") stops the program with IllegalArgumentException: No enum constant Size.HUGE. When the text comes from a user, convert it with toUpperCase() first, and later handle bad input with try-catch.

Using enums in a switch

Enums and switch are a great team. Inside the case labels you write just the constant name, without the enum prefix. With a switch expression (the arrow form), the compiler even checks that you handled every constant:

public class OrderTracker {
    public static void main(String[] args) {
        OrderStatus[] history = {
            OrderStatus.PLACED, OrderStatus.PREPARING, OrderStatus.OUT_FOR_DELIVERY, OrderStatus.DELIVERED
        };

        for (OrderStatus status : history) {
            String message = switch (status) {
                case PLACED -> "We got your order.";
                case PREPARING -> "The kitchen is cooking your food.";
                case OUT_FOR_DELIVERY -> "Your rider is on the way!";
                case DELIVERED -> "Enjoy your meal!";
                case CANCELLED -> "Your order was cancelled.";
            };
            System.out.println(status + ": " + message);
        }
    }
}

enum OrderStatus {
    PLACED, PREPARING, OUT_FOR_DELIVERY, DELIVERED, CANCELLED
}
PLACED: We got your order.
PREPARING: The kitchen is cooking your food.
OUT_FOR_DELIVERY: Your rider is on the way!
DELIVERED: Enjoy your meal!

This switch has no default branch, and it doesn't need one: all five constants are covered. If you later add a REFUNDED status and forget to update the switch, the compiler stops with the switch expression does not cover all possible input values. That's a bug caught before it ever reaches a customer.

Can an enum have fields, constructors and methods?

Yes, and this is where Java enums become really powerful. Each constant is an object, so it can carry its own data. Write the constants with arguments in parentheses, end the list with a semicolon, then add fields, a constructor and methods as in a normal class:

public class CoffeeBar {
    public static void main(String[] args) {
        for (CoffeeSize size : CoffeeSize.values()) {
            System.out.printf("%-6s %3d ml  $%.2f%n", size.label(), size.getMl(), size.getPrice());
        }

        CoffeeSize order = CoffeeSize.LARGE;
        System.out.printf("3 x %s = $%.2f%n", order.label(), order.priceFor(3));
    }
}

enum CoffeeSize {
    SMALL(240, 2.80),
    MEDIUM(350, 3.40),
    LARGE(470, 3.95);           // semicolon ends the list of constants

    private final int ml;
    private final double price;

    CoffeeSize(int ml, double price) {   // enum constructors are always private
        this.ml = ml;
        this.price = price;
    }

    int getMl() {
        return ml;
    }

    double getPrice() {
        return price;
    }

    double priceFor(int cups) {
        return price * cups;
    }

    String label() {
        return name().charAt(0) + name().substring(1).toLowerCase();
    }
}
Small  240 ml  $2.80
Medium 350 ml  $3.40
Large  470 ml  $3.95
3 x Large = $11.85
Animated diagram of the CoffeeSize enum: three fixed objects, SMALL with ordinal 0, 240 ml and 2.80 dollars, MEDIUM with ordinal 1, 350 ml and 3.40 dollars, and LARGE with ordinal 2, 470 ml and 3.95 dollars. A values() loop highlights each object in turn
Each enum constant is one object, created once, with its own field values. values() visits them in order.

Java creates the three objects once, when the enum is first used, by calling the constructor with the arguments you wrote. You can never call new CoffeeSize(...) yourself: the compiler says enum classes may not be instantiated. That guarantee is what makes == safe.

💡 Tip

Make enum fields private final. Constants are shared by the whole program, so their data should never change.

EnumMap: a map with enum keys

When you need to store a value for each enum constant, such as the stock count for each shirt size, Java offers EnumMap. It's a fast map that always keeps its keys in declaration order. (Maps are covered in Java HashMap; for now, a map links each key to a value.)

import java.util.EnumMap;
import java.util.Map;

public class StockCount {
    public static void main(String[] args) {
        Map<Size, Integer> stock = new EnumMap<>(Size.class);
        stock.put(Size.LARGE, 12);
        stock.put(Size.SMALL, 5);
        stock.put(Size.MEDIUM, 20);

        for (Map.Entry<Size, Integer> entry : stock.entrySet()) {
            System.out.println(entry.getKey() + " -> " + entry.getValue());
        }
    }
}

enum Size {
    SMALL, MEDIUM, LARGE
}
SMALL -> 5
MEDIUM -> 20
LARGE -> 12

Even though LARGE was added first, the map lists the sizes in the order the enum declares them.

Common mistakes with enums

1. Forgetting the semicolon after the constants

When an enum has fields or methods, the constant list must end with ;. Without it, the compiler gets confused by the field that follows.

2. Relying on ordinal() for stored data

ordinal() changes if someone reorders or inserts constants. Never save it to a file or database as an ID. Use name() or your own field instead.

3. Writing the enum name in case labels

In a switch on an enum, write case PLACED ->, not case OrderStatus.PLACED ->. Java 17 to 20 reject the qualified form; newer versions accept it, but the short form works everywhere.

4. Comparing with strings

status.equals("DELIVERED") compiles but is always false, because an enum is never equal to a String. Compare constants with status == OrderStatus.DELIVERED.

Practice exercise

🏋️ Try it yourself

Create a TrafficLight enum with the constants RED (30 seconds), GREEN (25 seconds) and YELLOW (5 seconds). Give it a seconds field, a getter, and a method next() that returns the following light (RED to GREEN to YELLOW and back to RED) using a switch expression. Starting at RED, print four steps of the cycle.

Show solution
public class Crossing {
    public static void main(String[] args) {
        TrafficLight light = TrafficLight.RED;
        for (int i = 0; i < 4; i++) {
            System.out.println(light + " for " + light.getSeconds() + " seconds");
            light = light.next();
        }
    }
}

enum TrafficLight {
    RED(30), GREEN(25), YELLOW(5);

    private final int seconds;

    TrafficLight(int seconds) {
        this.seconds = seconds;
    }

    int getSeconds() {
        return seconds;
    }

    TrafficLight next() {
        return switch (this) {
            case RED -> GREEN;
            case GREEN -> YELLOW;
            case YELLOW -> RED;
        };
    }
}
RED for 30 seconds
GREEN for 25 seconds
YELLOW for 5 seconds
RED for 30 seconds

What's next?

Enums are perfect for a fixed list of values. But what about classes whose only job is to carry a few pieces of data, like a point on a map or a product in a cart? Writing constructors, getters, equals(), hashCode() and toString() for them gets tiring. Next, learn how Java records write all of that for you.

Key takeaways

  • A Java enum is a special class with a fixed set of named constants, declared with the enum keyword.
  • Enums are type-safe: a variable of an enum type can only hold one of its constants (or null).
  • Each constant exists exactly once, so compare enum values with ==.
  • Built-in methods: values() lists all constants, ordinal() gives the position, name() gives the name and valueOf() converts a string.
  • A switch expression on an enum without default must cover every constant, so the compiler catches missing cases.
  • Enums can have private final fields, a private constructor and methods, giving each constant its own data.
  • EnumMap is an efficient map with enum keys that keeps them in declaration order.

Frequently asked questions

What is an enum in Java?

An enum is a special type that holds a fixed set of named constants, such as enum Size { SMALL, MEDIUM, LARGE }. Each constant is an object of that enum type, and the compiler only allows those values.

How do you loop through an enum in Java?

Call the built-in values() method, which returns an array of all constants in declaration order, and use a for-each loop: for (Size s : Size.values()) { ... }.

Should I use == or equals to compare enums?

Use ==. Each enum constant exists only once, so == is correct, a little faster and safe with null, whereas calling equals on a null variable would throw an exception.

Can a Java enum have a constructor?

Yes. An enum can have fields and a constructor, which is always private. Java calls it once for each constant, using the arguments written after the constant name, such as LARGE(470, 3.95).

What does ordinal() return in a Java enum?

ordinal() returns the zero-based position of the constant in the enum declaration. The first constant has ordinal 0. It changes if constants are reordered, so do not store it as a permanent ID.