Enums in Java

Naveen AnamaneniUpdated · 5 min read

A coffee shop sells three cup sizes. If sizes are stored as strings or ints, nothing stops someone from passing "LARGEE" or 7. An enum (enumeration) defines a type with a fixed set of named values, here SMALL, MEDIUM and LARGE, and the compiler rejects anything else. Java enums are much more than named numbers: each constant is a full object that can have fields, constructors and methods.

A Simple Enum

Cups.java▶ Try it
public class Cups {
    enum Size { SMALL, MEDIUM, LARGE }
 
    static int price(Size size) {
        return switch (size) {
            case SMALL -> 120;
            case MEDIUM -> 160;
            case LARGE -> 200;
        };
    }
 
    public static void main(String[] args) {
        Size order = Size.MEDIUM;
        System.out.println(order + " costs Rs. " + price(order));
        System.out.println(order == Size.MEDIUM);
    }
}
Output
MEDIUM costs Rs. 160
true

How it works

  1. enum Size { SMALL, MEDIUM, LARGE } declares a type with exactly three values. Constants are written in UPPER_CASE.
  2. A Size parameter can only receive one of those three (or null). price("LARGEE") wouldn't even compile.
  3. The switch covers all three constants, so the compiler knows it's exhaustive and needs no default.
  4. Each constant exists once, so comparing with == is safe and correct.

Fields, Constructors and Methods

Hard-coding prices in a switch spreads data around. An enum can carry its own data:

Each constant is one object with its own fields
Menu.java▶ Try it
public class Menu {
    enum Size {
        SMALL(250, 120),
        MEDIUM(350, 160),
        LARGE(500, 200);
 
        private final int ml;
        private final int price;
 
        Size(int ml, int price) {
            this.ml = ml;
            this.price = price;
        }
 
        int ml() { return ml; }
        int price() { return price; }
 
        double pricePer100ml() { return price * 100.0 / ml; }
    }
 
    public static void main(String[] args) {
        for (Size s : Size.values()) {
            System.out.printf("%-6s %3d ml  Rs. %d  (Rs. %.2f per 100 ml)%n",
                s, s.ml(), s.price(), s.pricePer100ml());
        }
    }
}
Output
SMALL  250 ml  Rs. 120  (Rs. 48.00 per 100 ml)
MEDIUM 350 ml  Rs. 160  (Rs. 45.71 per 100 ml)
LARGE  500 ml  Rs. 200  (Rs. 40.00 per 100 ml)

How it works

  1. Each constant passes arguments to the constructor: SMALL(250, 120).
  2. The constructor is implicitly private: only the constants themselves can be created, once, when the enum loads.
  3. Fields are private final (enum constants should be immutable), with methods to read them.
  4. values() returns all constants in declaration order.

Constant-Specific Behavior

Each constant can override a method with its own body:

Shipping.java▶ Try it
public class Shipping {
    enum Delivery {
        STANDARD {
            long charge(long amount) { return amount >= 499 ? 0 : 40; }
        },
        EXPRESS {
            long charge(long amount) { return 99; }
        },
        PICKUP {
            long charge(long amount) { return 0; }
        };
 
        abstract long charge(long amount);
    }
 
    public static void main(String[] args) {
        long cart = 350;
        for (Delivery d : Delivery.values()) {
            System.out.println(d + ": Rs. " + d.charge(cart));
        }
    }
}
Output
STANDARD: Rs. 40
EXPRESS: Rs. 99
PICKUP: Rs. 0

charge is declared abstract in the enum, so every constant must provide it. Adding a new delivery type without a charge rule becomes a compile error, which is far safer than a switch someone forgets to update.

Enums Can Implement Interfaces

An enum can't extend another class (it already extends java.lang.Enum), but it can implement interfaces:

Implements
interface Priced { int price(); }
 
enum Size implements Priced {
    SMALL(120), LARGE(200);
    private final int price;
    Size(int price) { this.price = price; }
    public int price() { return price; }
}

Common Mistakes

Using int or String constants for a fixed set of choices. Enums give type safety and readable names.

Mutable fields in enum constants. Constants are shared everywhere; keep their fields final.

Storing ordinal() in a database. Reordering the constants changes every ordinal; store name() (see "Enum Methods and Enums in Switch").

Interview Corner

What is an enum in Java, and how is it different from constants?

An enum is a special class with a fixed set of instances, its constants, each created once when the enum is initialized. Unlike int or String constants, an enum is type-safe: a method taking a Size can only receive a valid Size. Enums can have fields, private constructors, methods, constant-specific method bodies and can implement interfaces, and they work directly in switch.

Can an enum have a constructor? Can it extend a class?

It can have constructors, which are implicitly private and run once per constant. It can't extend a class, because every enum implicitly extends java.lang.Enum, but it can implement interfaces.

Practice

  1. Easy: Create an enum Day with the seven days and a method isWeekend().
  2. Harder: Create an enum Plan (BASIC, STANDARD, PREMIUM) with a monthly price and a number of screens. Print a table of all plans, and the cheapest plan that allows at least 2 screens.

Quick check: Enums

4 questions
1How do you compare two enum values?
2What access do enum constructors have?
3Can an enum extend another class?
4What does Size.values() return?

Key Takeaways

Was this tutorial helpful?

Lesson 165 of 482