Java Enums

In the last lesson you learned about Java static blocks. Now think about storing a day of the week or an order status, where only a few values are valid and anything else is a bug. An enum is the clean way to say β€œthis can only be one of these named choices”.

πŸ€” The problem enums solve

Say an app tracks an order status. It can be NEW, PAID, SHIPPED, or DELIVERED. The old way is plain int or String constants. Both go wrong.

public class Main {
static final int NEW = 0;
static final int PAID = 1;
static final int SHIPPED = 2;
static final int DELIVERED = 3;
public static void main(String[] args) {
int status = PAID;
System.out.println("Status code: " + status);
int broken = 99; // ❌ nobody stops you, but 99 is not a real status
System.out.println("Status code: " + broken);
}
}

This runs, but it is fragile.

  • Print status and you see 1, not PAID. That tells a reader nothing.
  • Nothing stops int broken = 99. The compiler is happy, but the bug shows up later.
  • Any method that takes int status accepts any integer.
  • The String version has its own trap. A typo like "payd" slips through silently. Spelling is on you, not the compiler.

What we want is a type that allows only a small fixed set of named values, and rejects everything else at compile time. That type is the enum.

🧩 What is an enum?

An enum is a special type that holds a fixed set of named constants. The word is short for β€œenumeration”, a listed set of choices. You declare one with the enum keyword, then list the values inside braces.

enum Day {
MON, TUE, WED, THU, FRI, SAT, SUN
}
public class Main {
public static void main(String[] args) {
Day today = Day.WED;
System.out.println("Today is " + today);
// Day wrong = Day.FUNDAY; // ❌ won't compile, FUNDAY is not a Day
}
}

Read the parts.

  • enum Day creates a new type called Day.
  • Each value, like MON, is a named constant of type Day. By convention they are uppercase.
  • You write Day.WED to pick a value, the name after the enum name and a dot.
  • Print it and you get the name itself, not a number.
  • Day.FUNDAY does not exist, so that line will not compile. A Day variable cannot hold an invalid value.

Output

Today is WED

βœ… Why enums beat int and String constants

An enum wins over loose constants in a few ways.

  • Type safety. A method that takes a Day only accepts a Day. Wrong values are caught while you write the code.
  • Readability. Printing an enum shows the real name, like WED, not a meaningless 2.
  • A closed set. The list lives in one place. The compiler keeps anything outside it out.

This method can only ever receive a real Day.

enum Day {
MON, TUE, WED, THU, FRI, SAT, SUN
}
public class Main {
static boolean isWeekend(Day day) {
return day == Day.SAT || day == Day.SUN;
}
public static void main(String[] args) {
System.out.println("Is SUN a weekend? " + isWeekend(Day.SUN));
System.out.println("Is MON a weekend? " + isWeekend(Day.MON));
// isWeekend(99); // ❌ won't compile
// isWeekend("Sunday"); // ❌ won't compile
}
}

The parameter type is Day, so you can only pass a real Day. The commented lines are rejected by the compiler. With int or String, those mistakes would compile fine and break later. Note we compared with ==. That is preferred for enums, because each constant is a single shared object. There is exactly one Day.SUN in the whole program.

Output

Is SUN a weekend? true
Is MON a weekend? false

πŸ”€ Using enums in switch and if

Enums shine inside switch. The values are fixed, so the switch reads cleanly. This prints a message for each order status.

enum Status {
NEW, PAID, SHIPPED, DELIVERED
}
public class Main {
static String describe(Status status) {
switch (status) {
case NEW:
return "Order placed, waiting for payment.";
case PAID:
return "Payment received, getting ready.";
case SHIPPED:
return "On the way to you.";
case DELIVERED:
return "Delivered. Enjoy!";
default:
return "Unknown status.";
}
}
public static void main(String[] args) {
System.out.println(describe(Status.PAID));
System.out.println(describe(Status.DELIVERED));
}
}

What to notice in the switch.

  • The labels are just NEW, PAID, and so on. You do not write case Status.NEW. Java knows the type already.
  • Each case maps one value to one message.
  • The default branch is a safety net for values added later.

Output

Payment received, getting ready.
Delivered. Enjoy!

You can also use enums in plain if checks with ==. Handy when you care about one or two values.

enum Direction {
NORTH, SOUTH, EAST, WEST
}
public class Main {
public static void main(String[] args) {
Direction heading = Direction.EAST;
if (heading == Direction.EAST) {
System.out.println("Heading east, toward the sunrise.");
} else {
System.out.println("Heading some other way.");
}
}
}

The check heading == Direction.EAST reads almost like English. No casting, no string matching.

Output

Heading east, toward the sunrise.

πŸ” Looping over values() with ordinal() and name()

Every enum gets a free method called values(). It returns an array of all the constants in declaration order. So you can loop over every value without listing them by hand.

enum Day {
MON, TUE, WED, THU, FRI, SAT, SUN
}
public class Main {
public static void main(String[] args) {
for (Day day : Day.values()) {
System.out.println(day.ordinal() + " -> " + day.name());
}
}
}

The two methods used here.

  • day.ordinal() gives the position, starting at 0. So MON is 0, TUE is 1.
  • day.name() gives the exact name as text, like "MON".
  • Output follows declaration order, so it is predictable. Great for building menus.

Output

0 -> MON
1 -> TUE
2 -> WED
3 -> THU
4 -> FRI
5 -> SAT
6 -> SUN

There is also valueOf(String), which goes the other way. It turns text back into the matching constant.

enum Status {
NEW, PAID, SHIPPED, DELIVERED
}
public class Main {
public static void main(String[] args) {
Status fromText = Status.valueOf("SHIPPED");
System.out.println("Got status: " + fromText);
System.out.println("Its position: " + fromText.ordinal());
}
}

Status.valueOf("SHIPPED") looks up the constant whose name is exactly "SHIPPED". The text must match, including case, or it throws an error. Useful when you read a status from a file or user input.

Output

Got status: SHIPPED
Its position: 2

🧱 Enums are full classes

Under the hood an enum is a full class, and each constant is an object of that class. So an enum can have fields, a constructor, and methods, just like a normal class.

enum Planet {
EARTH(9.8), MARS(3.7); // each constant passes a value to the constructor
private final double gravity; // a field
Planet(double gravity) { // a constructor
this.gravity = gravity;
}
public double getGravity() { // a method
return gravity;
}
}
public class Main {
public static void main(String[] args) {
System.out.println("Mars gravity: " + Planet.MARS.getGravity());
}
}

Do not worry about the details yet. The point is that an enum can carry data and behavior. Each constant is created once with its own value.

Output

Mars gravity: 3.7

More on this next

The next lesson goes deeper into enum fields, constructors, and methods. For now, the key takeaway is that enums are not limited to plain names. They are real classes that can hold real data.

⚠️ Common Mistakes

Here is how to spot and fix each one.

Using int or String constants instead of an enum. Loose constants throw away type safety. The enum stops bad values at compile time. The int version lets 99 or -5 through and breaks later.

static final int NEW = 0; // ❌ any int can be passed, no safety
void setStatus(int status) { }
enum Status { NEW, PAID, SHIPPED } // βœ… only a real Status is allowed
void setStatus(Status status) { }

Relying on the ordinal number as a stored value. The number depends on declaration order. Add or reorder a constant and every saved number points to the wrong value. Store name() instead, then read it back with valueOf().

// suppose you saved Status.PAID as the number 1
enum Status { NEW, PAID, SHIPPED } // PAID is 1
enum Status { NEW, CANCELLED, PAID, SHIPPED } // ❌ now PAID is 2, old data is wrong

Comparing enum names as strings. Just compare the constants directly. The == check is cleaner, and the compiler verifies that Day.SUN exists.

if (day.name().equals("SUN")) { } // ❌ fragile string match
if (day == Day.SUN) { } // βœ… direct, type-safe, faster

Forgetting a default in an enum switch. Add a new constant later and an old switch may quietly skip it. A default catches values you did not handle.

switch (status) {
case NEW: return "new";
case PAID: return "paid";
default: return "unknown"; // βœ… catches values you did not handle
}

βœ… Best Practices

  • Reach for an enum whenever values come from a small fixed set. Days, directions, statuses, sizes.
  • Name constants in uppercase, like MON or DELIVERED, so they stand out.
  • Compare enums with ==. Type-safe, readable, and avoids null surprises that equals can hide.
  • Store name(), not ordinal(). The name survives reordering. The number does not.
  • Keep a default in enum switches to protect against new constants.
  • Let methods take and return the enum type. Passing a Status instead of an int keeps the method honest.

🧩 What You’ve Learned

  • βœ… An enum is a special type that holds a fixed set of named constants, declared with enum Day { MON, TUE, ... }.
  • βœ… Enums give you type safety, readability, and a closed set that the compiler enforces, unlike int or String constants.
  • βœ… You can use enums cleanly in switch (with short labels) and in if checks with ==.
  • βœ… values() returns all constants for looping, ordinal() gives the position, and name() gives the text.
  • βœ… valueOf("TEXT") turns text back into the matching constant.
  • βœ… Enums are full classes that can have fields, constructors, and methods, which the next lesson explores.

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    What is a Java enum used for?

    Why: An enum defines a fixed, named set of allowed values, like the days of the week or order statuses.

  2. 2

    Why do enums beat int or String constants?

    Why: A method that takes an enum only accepts real enum values, so wrong values are stopped when you compile, not at runtime.

  3. 3

    What does values() return for an enum?

    Why: values() gives back an array of every constant, in the order you declared them, which is great for looping.

  4. 4

    Why should you avoid storing ordinal() as a saved value?

    Why: ordinal() is just the position in the list, so adding or reordering constants shifts the numbers and corrupts old data. Store name() instead.

πŸš€ What’s Next?

You have seen that enums are really full classes. Next we will give them real power by adding fields, constructors, and methods, so each constant can carry its own data and behavior.

Java Enum Methods

Share & Connect