Java Enums
Table of Contents + β
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
statusand you see1, notPAID. 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 statusaccepts any integer. - The
Stringversion 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 Daycreates a new type calledDay.- Each value, like
MON, is a named constant of typeDay. By convention they are uppercase. - You write
Day.WEDto pick a value, the name after the enum name and a dot. - Print it and you get the name itself, not a number.
Day.FUNDAYdoes not exist, so that line will not compile. ADayvariable 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
Dayonly accepts aDay. Wrong values are caught while you write the code. - Readability. Printing an enum shows the real name, like
WED, not a meaningless2. - 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? trueIs 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 writecase Status.NEW. Java knows the type already. - Each
casemaps one value to one message. - The
defaultbranch 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 at0. SoMONis0,TUEis1.day.name()gives the exact name as text, like"MON".- Output follows declaration order, so it is predictable. Great for building menus.
Output
0 -> MON1 -> TUE2 -> WED3 -> THU4 -> FRI5 -> SAT6 -> SUNThere 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: SHIPPEDIts 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.7The 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 safetyvoid setStatus(int status) { }
enum Status { NEW, PAID, SHIPPED } // β
only a real Status is allowedvoid 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 1enum Status { NEW, PAID, SHIPPED } // PAID is 1
enum Status { NEW, CANCELLED, PAID, SHIPPED } // β now PAID is 2, old data is wrongComparing 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 matchif (day == Day.SUN) { } // β
direct, type-safe, fasterForgetting 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
MONorDELIVERED, so they stand out. - Compare enums with
==. Type-safe, readable, and avoids null surprises thatequalscan hide. - Store
name(), notordinal(). The name survives reordering. The number does not. - Keep a
defaultin enum switches to protect against new constants. - Let methods take and return the enum type. Passing a
Statusinstead of anintkeeps 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
intorStringconstants. - β
You can use enums cleanly in
switch(with short labels) and inifchecks with==. - β
values()returns all constants for looping,ordinal()gives the position, andname()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
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
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
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
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.