Enums

An order can be PLACED, PACKED, SHIPPED or DELIVERED, and nothing else. If you store that as a String, someone will one day write "Shiped" and the compiler won't notice. An enum is a type with a fixed list of named values, checked by the compiler, and each value is a real object that can carry data and behaviour. You'll learn to declare, compare, switch on and extend enums, and see what Java builds behind the scenes.

Module 10 · Core Classes⏱ 22 minIntermediate8 practice problems
1 The story

The order that was never shipped

Kabir's shop app stores each order's status as a String. The warehouse code sets "Shipped", the delivery code checks for "SHIPPED", and a new teammate types "Shiped". Customers see “Processing” for days.

String status: anything goes status = "Shipped";warehouse status = "SHIPPED";delivery status = "Shiped";new code ✓ all compile ✗ none match enum Status: only these four PLACED PACKED SHIPPED DELIVERED status = Status.SHIPED; ✗ javac: cannot find symbol Typos are caught before the app runs. myphatshala.in
Riya

Sir, three people spelled “shipped” three ways, and Java was fine with all of them!

Arjun Sir

Because to Java they're just text. Any String is allowed. What you want is a type that has exactly four possible values. That's an enum: enum Status { PLACED, PACKED, SHIPPED, DELIVERED }.

Riya

And if someone types Status.SHIPED?

Arjun Sir

Compile error: cannot find symbol. And there's more: each value is a real object. It can carry data, like a delivery-time estimate, and methods, like “what's the next status?”. Let's build it.

2 Definition

What is an enum?

Formal definition (write this in exams)

An enum (enumeration type), declared with the keyword enum, is a special class that defines a fixed set of named constants. Each constant is a public static final instance of the enum, created once when the enum class is initialised. Every enum implicitly extends java.lang.Enum, so it cannot extend another class, but it may implement interfaces and declare fields, constructors (always private) and methods. Enum objects cannot be created with new. Introduced in Java 5.

In simple words

An enum is a list of the only allowed values for something: days of the week, order statuses, coach classes. The compiler stops anything else, and each value is an object you can give data and methods to.

Words you'll meet in this lesson

Enum constantOne of the declared values, e.g. Status.SHIPPED. Written in CAPITALS by convention.
name()The constant's name as a String: "SHIPPED".
ordinal()Its position in the declaration, starting at 0.
values()A static method that returns all constants in order, as an array.
valueOf(String)Finds a constant by its exact name; unknown names throw IllegalArgumentException.
Type-safeThe compiler only accepts values of the right type, so mistakes are caught early.
Implicit parentjava.lang.Enum<E>, so an enum can't extends anything else
ConstructorAlways private (writing public is a compile error); runs once per constant
Creating objectsNot allowed: new Status() is a compile error
Comparing== is safe and preferred: there is exactly one object per constant
Free methodsname(), ordinal(), toString(), compareTo(), values(), valueOf()

Exam tip: an enum is implicitly final (unless a constant has its own body) and extends java.lang.Enum; its constructor is implicitly private; the constants must be the first thing in the enum body, followed by a semicolon if anything else comes after them. Use == to compare enum values.

3 Types and ways to use it

Four ways to use an enum

1. Plain list

Just names: enum Day { MON, TUE, … }. Comes with values(), ordinal(), name().

fixed choices

2. In a switch

Branch on the value; inside case you write just SHIPPED.

decisions

3. With fields and methods

Each constant carries data: AC3(2.5), plus methods like fare(base).

rich constants

4. EnumMap / EnumSet

Fast, ordered collections keyed by enum constants.

collections

1. A plain enum and its built-in methods

import java.util.Arrays;

enum Status { PLACED, PACKED, SHIPPED, DELIVERED }

public class Main {
    public static void main(String[] args) {
        Status s = Status.SHIPPED;

        System.out.println(s);                 // toString() = name
        System.out.println(s.ordinal());       // position, from 0
        System.out.println(Arrays.toString(Status.values()));
        System.out.println(Status.valueOf("PACKED"));
        System.out.println(s == Status.SHIPPED);
        System.out.println(Status.PACKED.compareTo(Status.DELIVERED));  // by ordinal
    }
}
SHIPPED 2 [PLACED, PACKED, SHIPPED, DELIVERED] PACKED true -2

valueOf is exact: Status.valueOf("Shipped") or "SHIPED" throws IllegalArgumentException: No enum constant Status.SHIPED. When reading user input, normalise it (trim().toUpperCase()) and catch the exception.

2. Switch on an enum

enum Status { PLACED, PACKED, SHIPPED, DELIVERED }

public class Main {
    static String message(Status s) {
        return switch (s) {                       // switch expression (Java 14+)
            case PLACED, PACKED -> "We're preparing your order";
            case SHIPPED -> "On the way";
            case DELIVERED -> "Delivered. Enjoy!";
        };
    }

    public static void main(String[] args) {
        for (Status s : Status.values()) {
            System.out.println(s + ": " + message(s));
        }
    }
}
PLACED: We're preparing your order PACKED: We're preparing your order SHIPPED: On the way DELIVERED: Delivered. Enjoy!

Inside a case you write SHIPPED, not Status.SHIPPED. A switch expression over an enum must cover every constant (or have default), so if someone adds RETURNED later, javac points at every switch that forgot it.

3. Fields, a constructor and methods

enum Coach {
    SL(1.0), AC3(2.5), AC2(3.6);          // each constant calls the constructor

    private final double factor;

    Coach(double factor) {                 // private by default
        this.factor = factor;
    }

    int fare(int base) {
        return (int) Math.round(base * factor);
    }
}

public class Main {
    public static void main(String[] args) {
        for (Coach c : Coach.values()) {
            System.out.println(c + " fare for ₹400 base: ₹" + c.fare(400));
        }
    }
}
SL fare for ₹400 base: ₹400 AC3 fare for ₹400 base: ₹1000 AC2 fare for ₹400 base: ₹1440

Constants can even override a method each in their own way (constant-specific bodies):

enum Op {
    ADD { int apply(int a, int b) { return a + b; } },
    MUL { int apply(int a, int b) { return a * b; } };

    abstract int apply(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        System.out.println(Op.ADD.apply(3, 4) + " " + Op.MUL.apply(3, 4));
    }
}
7 12

4. EnumMap and EnumSet

import java.util.EnumMap;
import java.util.EnumSet;

enum Status { PLACED, PACKED, SHIPPED, DELIVERED }

public class Main {
    public static void main(String[] args) {
        EnumMap<Status, Integer> count = new EnumMap<>(Status.class);
        count.put(Status.DELIVERED, 5);
        count.put(Status.PLACED, 2);
        System.out.println(count);                       // always in declaration order

        EnumSet<Status> active = EnumSet.range(Status.PACKED, Status.SHIPPED);
        System.out.println(active.contains(Status.SHIPPED));
    }
}
{PLACED=2, DELIVERED=5} true

Rule of thumb: if a variable can only hold one of a small, fixed set of values known while coding (statuses, roles, sizes, payment modes), make it an enum. Don't use ordinal() for business data or database storage: inserting a new constant in the middle shifts every number. Store name() instead, or a code field of your own.

4 Step by step

What javac builds from an enum

  1. You write three words

    public enum Size { SMALL, MEDIUM, LARGE }
    javac compiles this into an ordinary class file, Size.class.
  2. It becomes a final class extending Enum

    public final class Size extends java.lang.Enum<Size> {
      public static final Size SMALL;
      public static final Size MEDIUM;
      public static final Size LARGE;
      private static final Size[] $VALUES;
      public static Size[] values();
      public static Size valueOf(java.lang.String);
      private Size();
      private static Size[] $values();
      static {};
    }
    Each constant is a public static final field. values() and valueOf() are generated for you. The constructor is private.
  3. The static initialiser creates the objects

    On first use of Size, the JVM runs static {}: it creates new Size("SMALL", 0), new Size("MEDIUM", 1), new Size("LARGE", 2) (javac passes the name and ordinal to Enum's constructor), stores them in the fields, and fills the $VALUES array.
  4. Every use refers to the same three objects

    Size.LARGE anywhere in the program reads the same static field, so it's the same object. That's why == is correct for enums, and why enums are a simple way to make a singleton.
  5. values() hands out a copy

    values() returns $VALUES.clone(): a new array each time, so callers can't change the real list. In a hot loop, store it once in a variable.
5 See it happen

From enum declaration to objects: both views

Left: the code. Right: the enum objects the JVM creates and the static fields pointing to them.

An enum's constants are created once 6 steps
What you see enum Coach { SL(1.0), AC3(2.5); … } Coach c = Coach.AC3; Coach d = Coach.AC3; println(c == d); println(c.fare(400)); Coach[] all = Coach.values(); Console true true 1000 true 1000 [SL, AC3] Declaring the enum creates nothing yet. First use of Coach. Use it again. Compare with ==. Call a method on the constant. Ask for all constants. myphatshala.in
Behind the screen Coach (static) Heap not initialised SL → AC3 → name "SL" ordinal 0 factor 1.0 name "AC3" ordinal 1 factor 2.5 main frame c → d → fare(400): 400 × 2.5 = 1000 new array [→SL, →AC3] (a copy) The enum class isn't initialised until first use. Static init: one object per constant. d gets the same object, no new one. One object, so == is true. The method reads this constant's field. values() copies the array of constants. myphatshala.in
6 Real-world use

Enums in real systems

Wherever a value must be one of a known list, production code reaches for an enum.

Watch it with an example: a delivery status page

A food-delivery order moves through an enum's states. Watch the app call next() and refuse a skip from PLACED straight to DELIVERED.

An order moving through enum states 5 steps
Animated example PLACED COOKING PICKED_UP DELIVERED skip? status = status.next(); status = Status.PLACED; App shows: Order received App shows: The restaurant is cooking App shows: Rider has picked up your food App shows: Delivered. Enjoy! label() comes from the constant's own field PLACED.canMoveTo(DELIVERED) → false a buggy request to skip ahead is refused myphatshala.in

1. Order and ticket statuses

E-commerce orders, support tickets and loan applications move through fixed states. An enum lists them, and often holds the allowed next states, so an order can't jump from PLACED to DELIVERED.

PLACED→status.next()→PACKED
UPICARDCOD

2. Payment modes with their own rules

A PaymentMode enum (UPI, CARD, NETBANKING, COD) can carry a fee percentage and a limit per mode, so the rules live with the value instead of in scattered if-else chains.

mode = CARD→mode.fee(amount)→₹ fee for that mode
ADMINTEACHER · STUDENT

3. Roles and permissions

A school portal's Role enum (ADMIN, TEACHER, STUDENT) with an EnumSet<Permission> per role makes access checks fast and readable.

user.role→role.can(Permission.EDIT_MARKS)→allow / deny
HttpStatus.NOT_FOUND

4. Libraries and the JDK

The JDK itself uses enums: DayOfWeek, Month, TimeUnit, RoundingMode, Thread.State. Web frameworks use them for HTTP methods and status codes.

LocalDate.getDayOfWeek()→DayOfWeek.SUNDAY→weekend pricing

Examples are simplified. When enums are saved to a database, teams store the name (or a stable code), never the ordinal.

7 Run the code

An order tracker that can't skip a step

enum Status {
    PLACED("Order received", 0),
    PACKED("Packed at warehouse", 1),
    SHIPPED("Out for delivery", 2),
    DELIVERED("Delivered", 0);

    private final String label;
    private final int daysLeft;

    Status(String label, int daysLeft) {
        this.label = label;
        this.daysLeft = daysLeft;
    }

    Status next() {
        if (this == DELIVERED) {
            return DELIVERED;                     // last step: stay
        }
        return values()[ordinal() + 1];           // the following constant
    }

    String label() { return label; }
    int daysLeft() { return daysLeft; }
}

public class Main {
    public static void main(String[] args) {
        Status s = Status.PLACED;
        while (s != Status.DELIVERED) {
            System.out.println(s + " · " + s.label() + " · " + s.daysLeft() + " day(s)");
            s = s.next();
        }
        System.out.println(s + " · " + s.label());
    }
}
PLACED · Order received · 0 day(s) PACKED · Packed at warehouse · 1 day(s) SHIPPED · Out for delivery · 2 day(s) DELIVERED · Delivered
  • PLACED("Order received", 0)Each constant passes its own data to the constructor, once, when the enum is initialised.
  • this == DELIVEREDComparing enums with == is safe: one object per constant.
  • values()[ordinal() + 1]Uses the declaration order to find the next status. Fine inside the enum; don't store ordinals elsewhere.
  • while (s != Status.DELIVERED)Outside the enum, constants need the type name: Status.DELIVERED.
8 Line by line

One object per constant

This trace is recorded from the real JVM. On the first line that uses Coach, the JVM initialises the enum class and creates every constant; the trace shows them already built. Look inside a constant on the heap: besides factor it carries name and ordinal, inherited from java.lang.Enum.

Worked examples: real problems, solved and traced in memory

Three business problems where an enum carries the rules. Watch method calls run on the constant objects.

Example 1Railways · fares

Total fare for a family booking

Problem statement

A family books 2 tickets in AC3 and 1 in SL on a route with a base fare of ₹400. Each coach class multiplies the base fare. Compute the total.

Input
AC3 × 2, SL × 1, base ₹400
Expected output
Total: ₹2400

Approach

  1. An enum Coach with a factor per constant and a method fare(base).
  2. A helper total(Coach[] seats, int base) adds up each seat's fare.
  3. Print the total.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 2Food delivery · states

Move an order to its next state

Problem statement

An order status enum has PLACED, COOKING, PICKED_UP and DELIVERED. Write next() so each call moves one step forward and DELIVERED stays DELIVERED, then print the journey.

Input
start at PLACED
Expected output
Final: DELIVERED after 3 steps

Approach

  1. Use ordinal() inside the enum to find the following constant in values().
  2. Return this for the last state.
  3. Loop in main until DELIVERED.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 3Payments · fees

Cheapest payment mode for an amount

Problem statement

Each payment mode has a fixed fee and a percentage fee: CARD ₹0 + 2%, NETBANKING ₹10 + 0%, WALLET ₹5 + 1%. For a ₹1500 purchase, find the cheapest mode.

Input
₹1500
Expected output
NETBANKING fee: ₹10

Approach

  1. Enum Mode with two fields and a method fee(amount).
  2. Start with the first constant as the best, then loop over values(), computing each fee once.
  3. Keep the mode with the smallest fee and print it.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

9 Quiz and revision

Check yourself

Quick revision

Lesson 10.4 in one screen

  • enum Status { PLACED, PACKED, SHIPPED }: a type with a fixed set of values, checked by javac.
  • Each constant is a public static final object, created once; compare with ==.
  • Built in: values(), valueOf(name) (exact, else IllegalArgumentException), name(), ordinal(), compareTo().
  • Switch: case SHIPPED ->; switch expressions must cover all constants.
  • Fields + private constructor + methods: AC3(2.5), fare(base). Constant-specific bodies for different behaviour.
  • Implicitly extends java.lang.Enum; can implement interfaces; can't be created with new.
  • Use EnumMap/EnumSet; store name(), not ordinal().

Interview and viva questions

Why use an enum instead of int or String constants?

Type safety (only declared values compile), readable names in logs and debuggers, built-in values()/valueOf(), use in switch with completeness checks, and the ability to attach data and behaviour. With public static final int constants, any int is accepted and a typo in a String constant isn't noticed.

Can an enum have a constructor? Can it be public?

Yes, it can have constructors, fields and methods. The constructor is always private (implicitly); declaring it public is a compile error, because only the enum itself may create its constants.

Can an enum extend a class or implement an interface?

It can't extend a class, because it already extends java.lang.Enum and Java has single inheritance. It can implement any number of interfaces, for example enum Mode implements FeeRule.

How do you make a singleton with an enum?

enum Config { INSTANCE; … }. The JVM guarantees one instance, creation is thread-safe (class initialisation), and serialization and reflection can't create a second copy. Joshua Bloch's Effective Java recommends it as the simplest singleton.

What's the difference between name() and toString()?

name() is final and always returns the declared name. toString() returns the name by default but can be overridden for display, e.g. “Out for delivery”. Use name() for storage and valueOf, toString() for people.

Practice problems

Declare enums, switch on them and give constants data and behaviour. The last three are business tasks.

P1Easy

Print all days with their positions

Declare enum Day { MON, TUE, WED, THU, FRI, SAT, SUN } and print each day with its ordinal.

Input
(none)
Expected output
MON=0 TUE=1 WED=2 THU=3 FRI=4 SAT=5 SUN=6 
Show solution and explanation
enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }

public class Main {
    public static void main(String[] args) {
        for (Day d : Day.values()) {
            System.out.print(d + "=" + d.ordinal() + " ");
        }
        System.out.println();
    }
}
MON=0 TUE=1 WED=2 THU=3 FRI=4 SAT=5 SUN=6

How it works: values() returns the constants in declaration order; ordinal() is the zero-based position.

P2Easy

Weekend or weekday?

Write isWeekend(Day d) using a switch expression and test SAT and WED.

Input
SAT, WED
Expected output
SAT: true
WED: false
Show solution and explanation
enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }

public class Main {
    static boolean isWeekend(Day d) {
        return switch (d) {
            case SAT, SUN -> true;
            default -> false;
        };
    }

    public static void main(String[] args) {
        System.out.println("SAT: " + isWeekend(Day.SAT));
        System.out.println("WED: " + isWeekend(Day.WED));
    }
}
SAT: true WED: false

How it works: a case can list several constants. default covers the remaining five.

P3Easy

Safe valueOf from user text

Convert " medium " and "huge" into Size values. Print MEDIUM for the first and Unknown size: huge for the second.

Input
" medium ", "huge"
Expected output
MEDIUM
Unknown size: huge
Show solution and explanation
enum Size { SMALL, MEDIUM, LARGE }

public class Main {
    static void read(String text) {
        try {
            System.out.println(Size.valueOf(text.trim().toUpperCase()));
        } catch (IllegalArgumentException e) {
            System.out.println("Unknown size: " + text.trim());
        }
    }

    public static void main(String[] args) {
        read(" medium ");
        read("huge");
    }
}
MEDIUM Unknown size: huge

How it works: valueOf needs the exact constant name, so normalise first and catch IllegalArgumentException for unknown values.

P4Medium

Planet weights

An enum Planet has a gravity factor relative to Earth: MERCURY 0.38, EARTH 1.0, JUPITER 2.53. Print the weight of a 60 kg person on each.

Input
60 kg
Expected output
MERCURY  22.8 kg
EARTH    60.0 kg
JUPITER  151.8 kg
Show solution and explanation
enum Planet {
    MERCURY(0.38), EARTH(1.0), JUPITER(2.53);

    private final double g;

    Planet(double g) { this.g = g; }

    double weight(double kg) { return kg * g; }
}

public class Main {
    public static void main(String[] args) {
        for (Planet p : Planet.values()) {
            System.out.printf("%-8s %.1f kg%n", p, p.weight(60));
        }
    }
}
MERCURY 22.8 kg EARTH 60.0 kg JUPITER 151.8 kg

How it works: each constant passes its own factor to the private constructor; the method uses this constant's field.

P5Medium

Calculator with constant-specific methods

Make enum Op with PLUS, MINUS and TIMES, each overriding apply(a, b). Print 8 op 2 for every op.

Input
8, 2
Expected output
8 PLUS 2 = 10
8 MINUS 2 = 6
8 TIMES 2 = 16
Show solution and explanation
enum Op {
    PLUS  { int apply(int a, int b) { return a + b; } },
    MINUS { int apply(int a, int b) { return a - b; } },
    TIMES { int apply(int a, int b) { return a * b; } };

    abstract int apply(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        for (Op op : Op.values()) {
            System.out.println("8 " + op + " 2 = " + op.apply(8, 2));
        }
    }
}
8 PLUS 2 = 10 8 MINUS 2 = 6 8 TIMES 2 = 16

How it works: the enum declares an abstract method and each constant supplies its own body. javac compiles each body into a small subclass (Op$1, Op$2, …).

P6Business problem

Count orders by status

Given statuses of 6 orders, count how many are in each status using an EnumMap, printed in the enum's order.

Input
PACKED, PLACED, SHIPPED, PACKED, DELIVERED, PACKED
Expected output
{PLACED=1, PACKED=3, SHIPPED=1, DELIVERED=1}
Show solution and explanation
import java.util.EnumMap;

enum Status { PLACED, PACKED, SHIPPED, DELIVERED }

public class Main {
    public static void main(String[] args) {
        Status[] orders = {Status.PACKED, Status.PLACED, Status.SHIPPED,
                           Status.PACKED, Status.DELIVERED, Status.PACKED};
        EnumMap<Status, Integer> count = new EnumMap<>(Status.class);
        for (Status s : orders) {
            count.put(s, count.getOrDefault(s, 0) + 1);
        }
        System.out.println(count);
    }
}
{PLACED=1, PACKED=3, SHIPPED=1, DELIVERED=1}

How it works: an EnumMap is backed by an array indexed by ordinal, so it's fast and always iterates in declaration order.

P7Business problem

Role-based permissions

Roles ADMIN, TEACHER and STUDENT each have a set of allowed actions (VIEW, EDIT_MARKS, DELETE_USER). Check whether a TEACHER may EDIT_MARKS and DELETE_USER.

Input
TEACHER: EDIT_MARKS?, DELETE_USER?
Expected output
TEACHER EDIT_MARKS: true
TEACHER DELETE_USER: false
Show solution and explanation
import java.util.EnumSet;

enum Action { VIEW, EDIT_MARKS, DELETE_USER }

enum Role {
    ADMIN(EnumSet.allOf(Action.class)),
    TEACHER(EnumSet.of(Action.VIEW, Action.EDIT_MARKS)),
    STUDENT(EnumSet.of(Action.VIEW));

    private final EnumSet<Action> allowed;

    Role(EnumSet<Action> allowed) { this.allowed = allowed; }

    boolean can(Action a) { return allowed.contains(a); }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("TEACHER EDIT_MARKS: " + Role.TEACHER.can(Action.EDIT_MARKS));
        System.out.println("TEACHER DELETE_USER: " + Role.TEACHER.can(Action.DELETE_USER));
    }
}
TEACHER EDIT_MARKS: true TEACHER DELETE_USER: false

How it works: each role carries its own EnumSet of actions; the permission rule is one method on the enum.

P8Business problem

GST slab by category

Product categories have GST rates: ESSENTIAL 5%, STANDARD 18%, LUXURY 28%. Print the final price of ₹1000 items in each category.

Input
₹1000
Expected output
Essential: ₹1050
Standard: ₹1180
Luxury: ₹1280
Show solution and explanation
enum Category {
    ESSENTIAL(5), STANDARD(18), LUXURY(28);

    private final int gstPct;

    Category(int gstPct) { this.gstPct = gstPct; }

    int withGst(int price) { return price + price * gstPct / 100; }

    @Override
    public String toString() { return name().charAt(0) + name().substring(1).toLowerCase(); }
}

public class Main {
    public static void main(String[] args) {
        for (Category c : Category.values()) {
            System.out.println(c + ": ₹" + c.withGst(1000));
        }
    }
}
Essential: ₹1050 Standard: ₹1180 Luxury: ₹1280

How it works: the rate lives with the category. Overriding toString() gives friendly text, while name() still returns ESSENTIAL for storage. (Simplified: real GST rates are set per HSN code and change by notification.)

Real-world scenario questions (asked in company interviews)

Enum questions in interviews are often about design: where should the rules live, and what happens when the list changes?

E-commerce · designFresher

Replace status Strings

An order service stores status as a String and has bugs from inconsistent spelling. How would you refactor it?

The interviewer is checking: do you know when an enum is the right tool?

Show a strong answer
  • Create enum OrderStatus { PLACED, PACKED, SHIPPED, DELIVERED, CANCELLED } and change the field type. javac now flags every wrong value.
  • Convert at the edges only: OrderStatus.valueOf(text.trim().toUpperCase()) with error handling when reading requests; name() when writing to the database.
  • Move rules into the enum, e.g. canMoveTo(OrderStatus next), so transitions are checked in one place.

Avoid: storing the ordinal in the database “to save space”. Adding a status in the middle silently corrupts old rows.

Payments · maintainabilityJunior

Fees spread across ten if-else chains

Fee logic for UPI, card, net banking and COD is copied in ten places as if (mode.equals("CARD")) …. Adding a new mode means editing all ten. What do you propose?

The interviewer is checking: putting behaviour on enum constants.

Show a strong answer
  • An enum PaymentMode with fields (fee percent, max amount) and a method fee(amount), or constant-specific bodies when the formulas differ.
  • Callers do mode.fee(amount). A new mode is one new constant; switch expressions elsewhere fail to compile until they handle it.
  • If fees change often or per merchant, keep the enum for the mode but load numbers from configuration.

Avoid: hard-coding values that the business changes weekly. Enums suit things that change with code releases.

API · backward compatibilityMid

A new constant breaks an old client

Your service adds RETURNED to OrderStatus. An older mobile app that deserialises the status with valueOf now crashes for returned orders. How do you prevent this?

The interviewer is checking: evolving enums across systems.

Show a strong answer
  • Clients should handle unknown values: catch IllegalArgumentException and map to an UNKNOWN constant (many JSON libraries have an option for this).
  • Roll out client support before the server starts sending new values; version the API if needed.
  • Document the enum as “may grow” in the API contract.

Avoid: “never add constants”. Business changes; plan for it.

Platform · singletonJunior

Exactly one configuration object

You need one shared AppConfig object for the whole application, created safely even if two threads ask for it at start-up. What's the simplest correct way in Java?

The interviewer is checking: knowledge of the enum singleton.

Show a strong answer
  • enum AppConfig { INSTANCE; private final Properties props = load(); … }.
  • The JVM creates INSTANCE once during class initialisation, which is thread-safe, and enums are protected against extra copies through reflection and serialization.
  • In larger apps, a dependency-injection container (e.g. Spring) usually manages singletons instead.

Avoid: double-checked locking without volatile. It's easy to get wrong.