⚡IntermediateAdvanced OOP

Enums

Define a fixed set of named constants with enum, and add fields, methods, and abstract methods to make them powerful.

Overview

An enum (enumeration) defines a type with a fixed set of named constants. Unlike plain int constants, enums are type-safe: the compiler prevents you from passing an invalid value where an enum is expected. Java enums are more powerful than enums in most other languages. Each constant is a singleton object of the enum type. Enums can have fields, constructors, and methods. You can even declare abstract methods that each constant implements differently.

Key Points

  • •enum Season { SPRING, SUMMER, AUTUMN, WINTER }
  • •Enum constants are implicitly public static final instances of the enum type
  • •values() returns all constants as an array; ordinal() gives the position (0-based)
  • •name() returns the constant name as a String; valueOf("NAME") retrieves by name
  • •Enums can have fields and a constructor called once per constant definition
  • •Enums can have methods, including abstract methods overridden per constant
  • •Enums implement interfaces
  • •Use switch with enums for clean dispatch

Examples

Basic enum and switch

public class Main {
    enum Direction { NORTH, SOUTH, EAST, WEST }

    static String describe(Direction d) {
        return switch (d) {
            case NORTH -> "Go north";
            case SOUTH -> "Go south";
            case EAST  -> "Go east";
            case WEST  -> "Go west";
        };
    }

    public static void main(String[] args) {
        Direction dir = Direction.NORTH;
        System.out.println(dir);              // NORTH
        System.out.println(dir.ordinal());    // 0
        System.out.println(dir.name());       // NORTH
        System.out.println(describe(dir));    // Go north

        for (Direction d : Direction.values()) {
            System.out.println(d + " = " + d.ordinal());
        }
    }
}

The switch expression with enum is exhaustive: the compiler knows all possible values, so no default is needed here.

Enum with fields and constructor

public class Main {
    enum Planet {
        MERCURY(3.303e+23, 2.4397e6),
        VENUS  (4.869e+24, 6.0518e6),
        EARTH  (5.976e+24, 6.37814e6),
        MARS   (6.421e+23, 3.3972e6);

        private final double mass;   // kg
        private final double radius; // m

        Planet(double mass, double radius) {
            this.mass = mass;
            this.radius = radius;
        }

        static final double G = 6.67300E-11;

        double surfaceGravity() { return G * mass / (radius * radius); }
        double surfaceWeight(double otherMass) { return otherMass * surfaceGravity(); }
    }

    public static void main(String[] args) {
        double earthWeight = 75.0;
        double mass = earthWeight / Planet.EARTH.surfaceGravity();
        for (Planet p : Planet.values()) {
            System.out.printf("Weight on %s: %.2f N%n", p, p.surfaceWeight(mass));
        }
    }
}

Each enum constant calls the constructor with its own values. Fields can be accessed via methods, making enum constants full-featured objects.

Enum with abstract method

public class Main {
    enum Operation {
        PLUS("+") {
            @Override public double apply(double x, double y) { return x + y; }
        },
        MINUS("-") {
            @Override public double apply(double x, double y) { return x - y; }
        },
        TIMES("*") {
            @Override public double apply(double x, double y) { return x * y; }
        },
        DIVIDE("/") {
            @Override public double apply(double x, double y) { return x / y; }
        };

        private final String symbol;

        Operation(String symbol) { this.symbol = symbol; }

        public abstract double apply(double x, double y);

        @Override public String toString() { return symbol; }
    }

    public static void main(String[] args) {
        double x = 10, y = 3;
        for (Operation op : Operation.values()) {
            System.out.printf("%.1f %s %.1f = %.2f%n", x, op, y, op.apply(x, y));
        }
    }
}

Abstract methods in enums must be overridden by every constant. This is cleaner than a switch on the operation type.

Common Mistakes

  • Comparing enum constants with equals instead of ==. Enums are singletons, so == is both correct and faster
  • Expecting ordinal() to be stable across code changes. If you insert a constant in the middle, all following ordinals shift. Never persist ordinal values; use name() or a dedicated field instead
  • Calling valueOf("invalid") which throws IllegalArgumentException. Wrap in try-catch or iterate values() if the input may not match

Note

EnumSet and EnumMap are specialised, highly efficient implementations for sets and maps whose elements or keys are enum constants. Prefer them over HashSet and HashMap when working with enums.

Exercises

Write Java code and click Run to execute it instantly. When your output looks correct, mark as done.

Loading editor…

Completed: 0 / 4 exercises

Knowledge Check

Question 1 of 4

Which method returns all constants of an enum as an array?