Enum in Java: A Complete Beginner’s Guide with Examples
-
Last Updated: July 29, 2026
-
By: javahandson
-
Series
Learn Java in a easy way
Learn what an enum in Java is, how to declare one, and how to use fields, constructors, methods, switch, EnumSet, and EnumMap — with clear beginner examples.
You’ve probably had a value that can only be one of a few fixed things. A day of the week. A traffic light color. An order status like PENDING or SHIPPED. You could store these as plain strings or numbers, but that gets messy fast.
That’s the exact problem an enum in Java solves. An enum lets you define a small, fixed set of named values. Once you have it, the compiler stops you from using anything outside that set.
Think of a traffic light. It shows RED, YELLOW, or GREEN. It never shows PURPLE. An enum captures that idea in code, so your program can only ever use the values you allow.
In this article, we’ll start with what an enum really is. Then we’ll build up from tiny examples to the powerful stuff, like enums with fields, methods, and constructors.
We’ll keep every example short and runnable. You can copy each one into your editor and try it right away. That’s the best way to make enums stick.
Here’s what we’ll cover:
No deep background needed. If you can write a simple Java class, you’re ready to go.

An enum is a special type that holds a fixed group of constants. The word enum is short for enumeration, which just means a listing of items.
Each value in an enum is called a constant. You write them in capital letters by convention. And each one is a real object, not just a label.
You define an enum once, up front. After that, those are the only values allowed. Nothing else can ever be that type.
Before enums, people stored fixed choices as strings. A status field might hold “ACTIVE” or “INACTIVE”. It works, but it’s risky.
Say you type “Actve” by mistake. The code still compiles. The bug only shows up later, at runtime, when something breaks.
Strings give you no safety net here. Any text is a valid string, even nonsense. So the compiler can’t warn you about a wrong value.
With an enum, a typo won’t compile. You can only use the constants you defined. The compiler catches the error right away, which saves you real debugging time.
Another old trick was using plain int values. You might write a set of static final ints like this:
public static final int RED = 0; public static final int YELLOW = 1; public static final int GREEN = 2;
This has problems too. Nothing stops you from passing 7 where a color is expected. The number 7 isn’t a color, but the compiler won’t complain.
Also, when you print the value, you just see a number. You lose the friendly name. An enum keeps the name and blocks bad values, so you get the best of both.
Here’s the big win. An enum gives you type safety. A method that takes a Color can only accept Color values, never a random int or string.
So your code says what it means. And the compiler enforces it. Bad values simply can’t sneak in through the front door.
Let’s make that concrete. Imagine a method that sets a traffic light. With an enum, the signature reads setLight(Color c). Anyone reading it knows exactly what to pass.
Compare that to setLight(int c). Now the reader has to guess. Is 0 red or green? Is 5 even valid? The enum removes all that doubt.
This part surprises a lot of beginners. Each enum constant is a full-blown object. It’s created once, and Java keeps just one copy of it.
Because there’s only one copy, you can safely compare with ==. Two references to Day.MONDAY point at the very same object in memory.
This single-instance behavior also makes enums a clean way to write a singleton. We’ll touch on that later when we cover constructors.
It helps to see the three approaches side by side. All three can model a fixed choice. But they don’t offer the same safety.
| Feature | String | int constant | Enum |
|---|---|---|---|
| Type-safe | No | No | Yes |
| Typo caught at compile time | No | No | Yes |
| Readable output | Yes | No | Yes |
| Can hold extra data | No | No | Yes |
| Works in switch | Yes | Yes | Yes |
| Fixed set enforced | No | No | Yes |
The enum column wins almost every row. That’s why modern Java code leans on enums for any small, fixed set of options.
A good rule of thumb helps here. Use an enum whenever a value can only be one of a few known choices.
Some everyday examples fit this perfectly:
If the list is small and known ahead of time, an enum fits. If the values change at runtime or come from users, a plain collection is better.
Let’s write our first enum. It’s just the enum keyword, a name, and a list of constants.
Here’s a Day enum with three values. Notice the constants are in capitals, separated by commas.
public enum Day {
MONDAY,
TUESDAY,
WEDNESDAY
}That’s the whole thing. No fields, no methods, just three named constants. You can already use it in your code.
You use an enum value by name, through the type. It reads cleanly and stays type-safe.
Day today = Day.MONDAY;
System.out.println(today); // Output: MONDAY
if (today == Day.MONDAY) {
System.out.println("Start of the work week");
}See how we compare with ==? For enums, that’s safe and preferred. Each constant is a single shared object, so == checks identity correctly.
You don’t need equals() here, though it also works. Most Java developers use == with enums because it reads well and never throws a NullPointerException on the left side.
You can define an enum in its own file, just like a class. You can also nest it inside a class when it’s only used there.
Pick the spot that keeps your code tidy. For shared values like order status, a top-level enum usually makes the most sense.
There’s a simple convention for enum constants. Write them in all capitals, with underscores between words.
So you’d write IN_PROGRESS, not inProgress or InProgress. This matches how Java names other constants, and it makes them easy to spot.
The enum type name itself follows normal class rules. Use PascalCase, like OrderStatus or TrafficLight. Small habits like this keep your code readable.
Every enum you write comes with handy methods for free. Java adds them behind the scenes. Let’s look at the ones you’ll actually use.
The values() method returns an array of every constant, in the order you declared them. It’s perfect for looping.
for (Day d : Day.values()) {
System.out.println(d);
}
// Output:
// MONDAY
// TUESDAY
// WEDNESDAYThis is great for building menus, filling dropdowns, or iterating over every option. No manual list needed.
Sometimes you have a string, maybe from user input or a database, and you want the matching enum. Use valueOf() for that.
Day d = Day.valueOf("TUESDAY");
System.out.println(d); // Output: TUESDAYOne catch. The string must match a constant name exactly, including case. If it doesn’t, valueOf() throws an IllegalArgumentException. So guard your input first.
The ordinal() method returns the position of a constant, starting at 0. The first constant is 0, the second is 1, and so on.
System.out.println(Day.MONDAY.ordinal()); // 0 System.out.println(Day.WEDNESDAY.ordinal()); // 2
Be careful with ordinal() though. Don’t save it in a database or file. If you reorder your constants later, every stored number now points at the wrong value.
The name() method returns the constant’s name as a string, exactly as declared. It’s similar to toString(), but you should not override it.
System.out.println(Day.MONDAY.name()); // MONDAY
Use name() when you want the guaranteed, unchanged constant name. Use toString() when you want a display value you might customize.
Let’s see these methods work together. Say you get a status string from a web form. You want to turn it into an enum, safely.
String input = "TUESDAY";
try {
Day day = Day.valueOf(input);
System.out.println("Got: " + day.name());
} catch (IllegalArgumentException e) {
System.out.println("Not a valid day: " + input);
}This guards against bad input. A good value becomes an enum. A bad value gets caught, and your program keeps running instead of crashing.
That little try-catch is a habit worth keeping. Any time a string comes from outside your code, wrap valueOf() so a typo can’t take you down.
Here they are side by side, so you can pick the right one quickly.
| Method | Returns | Common Use |
|---|---|---|
| values() | Array of all constants | Loop over every option |
| valueOf(String) | Matching constant | Convert text to enum |
| ordinal() | Position as int | Rarely, for internal order |
| name() | Constant name as String | Get the exact declared name |
Here’s where enums get powerful. A Java enum is a full class under the hood. So it can hold data and behavior, not just names.
Say each planet should carry its own mass. You can attach a value to each constant with a field and a constructor.
public enum Coin {
PENNY(1),
NICKEL(5),
DIME(10),
QUARTER(25);
private final int cents;
Coin(int cents) {
this.cents = cents;
}
public int getCents() {
return cents;
}
}Each constant now passes a value into the constructor. PENNY gets 1, NICKEL gets 5, and so on. The value rides along with the constant.
Enum constructors follow a couple of rules that trip up newcomers. Keep these in mind:
That private constructor is the whole point. Java builds each constant a single time, and no one else can create more. That’s why enums make great singletons.
Now you can ask any constant for its data. Just call the getter you wrote.
Coin c = Coin.QUARTER;
System.out.println(c.getCents()); // 25
int total = 0;
for (Coin coin : Coin.values()) {
total += coin.getCents();
}
System.out.println(total); // 41So each coin knows its own worth. This beats a scattered map of values, because the data lives right next to the constant it describes.
Enums can hold methods too. You can even give each constant its own version of a method. This is called a constant-specific method body.
public enum Operation {
PLUS {
public int apply(int a, int b) { return a + b; }
},
MINUS {
public int apply(int a, int b) { return a - b; }
};
public abstract int apply(int a, int b);
}Here each operation carries its own logic. PLUS adds, MINUS subtracts. You call apply() and the right code runs for that constant.
System.out.println(Operation.PLUS.apply(3, 4)); // 7 System.out.println(Operation.MINUS.apply(10, 4)); // 6
This pattern replaces long if-else chains. Each constant owns its behavior, so the code stays clean and easy to extend.
| 💡 Interview Insight Q: Can a Java enum have a constructor? A: Yes, but it must be private (or package-private). You can’t call it with new. Java runs the constructor once for each constant when the enum type loads. |
An enum can’t extend a class, but it can implement an interface. This lets your constants fit into code that expects a certain contract.
interface Describable {
String describe();
}
public enum Size implements Describable {
SMALL, MEDIUM, LARGE;
public String describe() {
return "Size: " + name();
}
}Now any Size value can be treated as a Describable. So your enum plugs neatly into general-purpose methods, without giving up its fixed set of values.
Sometimes you have a stored value and want the matching constant back. A small static helper handles this cleanly.
Say each coin has a cents value, and you want the coin for 25. You can loop over values() and return the match.
public static Coin fromCents(int cents) {
for (Coin c : Coin.values()) {
if (c.getCents() == cents) {
return c;
}
}
throw new IllegalArgumentException("No coin for " + cents);
}Now Coin.fromCents(25) gives you QUARTER. This pattern is common when you map a database column back to an enum.
For large enums, you’d cache the lookups in a static map instead. But for a handful of constants, this simple loop is perfectly fine.
Here’s a neat trick many developers love. An enum is one of the cleanest ways to write a singleton in Java.
A singleton is a class with exactly one instance. You want just one shared object, and no way to make more. Enums give you that for free.
Recall that Java creates each enum constant once. It also blocks you from calling the constructor yourself. Those two facts are exactly what a singleton needs.
So a single-constant enum is a ready-made singleton. No extra locking, no double-check logic, no clever code. Java handles it all.
public enum Config {
INSTANCE;
private String appName = "MyApp";
public String getAppName() {
return appName;
}
}There’s just one constant, INSTANCE. That’s your single object. You reach it with Config.INSTANCE, and there’s no way to make a second one.
You call methods on the single instance directly. It reads clean and stays safe across threads.
String name = Config.INSTANCE.getAppName(); System.out.println(name); // MyApp
This approach is also safe when many threads run at once. Java guarantees the constant is built once, correctly, before anyone uses it.
It even survives serialization cleanly, which trips up hand-written singletons. For these reasons, many experts call the enum singleton the best one.
| 💡 Interview Insight Q: Why is an enum considered the best way to write a singleton? A: Java creates the single constant once, blocks extra instances, and handles thread safety and serialization for you. A hand-written singleton needs careful locking and readResolve logic to match that. |
Enums and switch statements are a natural fit. The switch reads clean, and the compiler helps you catch missing cases.
Inside a switch on an enum, you write just the constant name in each case. You don’t repeat the enum type.
Day today = Day.MONDAY;
switch (today) {
case MONDAY:
System.out.println("Back to work");
break;
case TUESDAY:
System.out.println("Second day");
break;
default:
System.out.println("Some other day");
}Notice we write case MONDAY, not case Day.MONDAY. Java already knows the type from the switch. Adding the prefix is actually a compile error.
A switch on an enum makes your intent clear. And many tools warn you when you forget a case. That warning is a small gift that prevents bugs.
For that reason, enums pair really well with switch logic. State machines, menu handlers, and status flows all benefit from this combo.
Modern Java also offers a cleaner switch that returns a value. It uses arrows and skips the break statements. Many teams prefer it now.
String message = switch (today) {
case MONDAY -> "Back to work";
case TUESDAY -> "Second day";
default -> "Some other day";
};
System.out.println(message);No break needed, and each arm returns a value. So the whole block reads as one clear expression. It’s a nice fit for enums.
| 💡 Interview Insight Q: Do you write case Day.MONDAY or case MONDAY inside a switch? A: Just case MONDAY. The switch already knows the enum type, so writing the qualified name causes a compile error. |
Java gives you two special collections built just for enums. They’re called EnumSet and EnumMap. Both are fast and memory-light.
An EnumSet holds a group of enum constants. Under the hood, it uses bits, so it’s very compact and quick.
EnumSet<Day> workStart = EnumSet.of(Day.MONDAY, Day.TUESDAY);
if (workStart.contains(Day.MONDAY)) {
System.out.println("Monday is in the set");
}Use EnumSet instead of HashSet when your keys are enum constants. It’s faster and uses less memory, with no real downside.
An EnumMap maps each enum constant to a value. It’s like a HashMap, but tuned for enum keys.
EnumMap<Day, String> plans = new EnumMap<>(Day.class); plans.put(Day.MONDAY, "Team meeting"); plans.put(Day.TUESDAY, "Code review"); System.out.println(plans.get(Day.MONDAY)); // Team meeting
Because it knows the enum ahead of time, EnumMap stores values in a plain array. That makes lookups quick and the memory footprint small.
EnumSet comes with a few nice factory methods. You can grab all constants, none of them, or a range, in one line.
EnumSet<Day> all = EnumSet.allOf(Day.class); EnumSet<Day> none = EnumSet.noneOf(Day.class); EnumSet<Day> some = EnumSet.range(Day.MONDAY, Day.WEDNESDAY);
These read almost like plain English. So building a set of permissions or flags stays short and easy to follow.
Let’s tie the pieces together with a small, realistic task. Say you’re modeling an order in a shopping app.
An order moves through a few fixed states. It’s created, then paid, then shipped, then delivered. That’s a perfect fit for an enum.
public enum OrderStatus {
CREATED("Order placed"),
PAID("Payment received"),
SHIPPED("On the way"),
DELIVERED("Delivered");
private final String label;
OrderStatus(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}Each status carries a friendly label. So you can show “On the way” in the UI while your code still works with the clean SHIPPED constant.
Now you handle each state with a switch. The compiler and your tools help you cover every case.
OrderStatus status = OrderStatus.SHIPPED;
switch (status) {
case CREATED:
System.out.println("Waiting for payment");
break;
case PAID:
System.out.println("Preparing your order");
break;
case SHIPPED:
System.out.println(status.getLabel());
break;
case DELIVERED:
System.out.println("Enjoy!");
break;
}Clean and readable, right? Each state maps to one clear action. Adding a new status later is easy, and your tools remind you to handle it.
When you save an order, store the name, not the ordinal. That way, reordering constants later never corrupts your old data.
String toSave = status.name(); // "SHIPPED" OrderStatus loaded = OrderStatus.valueOf(toSave);
This round-trip is safe and clear. You write a stable string, and you read it back into the exact same constant.
Look at what this small enum gave you. The order can only ever be one of four states. No stray string can slip in.
Each state carries its own label for the screen. And the switch makes your logic easy to read at a glance.
Later, if you add a RETURNED state, you edit one enum. Your tools then flag every switch that needs the new case. That’s a lot of safety from a few lines.
A few simple habits make your enums cleaner and safer. None of them are hard. They just save you trouble down the road.
When you save an enum, write its name(), not its ordinal(). Names stay stable even if you reorder or add constants later.
This one habit prevents a whole class of nasty data bugs. So make it your default from day one.
If behavior depends on the constant, put it in the enum itself. A method or a field beats a big switch scattered across your code.
That way, adding a constant means updating one place. Your logic and your data stay together, which is easier to maintain.
Whenever your keys are enum constants, reach for EnumSet or EnumMap. They’re faster and lighter than the general-purpose versions.
There’s really no downside here. So treat these two as the default choice for enum-keyed collections.
A few enum traps catch beginners over and over. Let’s name them so you can steer clear.
This one hurts later. If you save ordinal() and then reorder your constants, every stored number now points at the wrong value. Store name() instead, since names stay stable.
The valueOf() method matches names exactly. Pass “monday” for a MONDAY constant and it throws. Normalize your input, or wrap the call in a try-catch.
In an enum with fields, the constants must come first. Put a field before them and the code won’t compile. Always list your constants at the top.
You can’t make one enum extend another. Every enum already extends java.lang.Enum, and Java allows only one parent. Enums can implement interfaces, though, which covers most needs.
A: An enum is a special type that holds a fixed set of named constants. Each constant is a real object, created once. Enums are type-safe, so the compiler blocks any value outside the set you defined.
A: Yes. The constructor must be private or package-private, and you cannot call it with new. Java runs it once for each constant when the enum type loads.
A: name() returns the constant’s exact declared name as a string. ordinal() returns its position, starting at 0. Store name() for persistence, since ordinal values shift if you reorder constants.
A: Each enum constant is a single shared object, so == compares identity correctly. It also reads well and never throws a NullPointerException on the left side.
A: No. Every enum already extends java.lang.Enum, and Java allows only one parent. An enum can implement interfaces, though, which covers most needs.
A: Use EnumSet when you need a group of enum constants, and EnumMap when you map enum keys to values. Both are faster and lighter than HashSet or HashMap for enum keys.
A: Yes. The string must match a constant name exactly, including case. A mismatch throws IllegalArgumentException, so normalize input or wrap the call in a try-catch.
A: Just case MONDAY. The switch already knows the enum type, so adding the qualified name causes a compile error.
Let’s pull it together. An enum in Java defines a fixed set of named constants. It’s type-safe, readable, and blocks bad values at compile time.
You saw the basics first: declaring constants, comparing with ==, and looping with values(). Then you went further, with fields, constructors, and constant-specific methods.
You also met switch statements, EnumSet, and EnumMap. Each one makes enum-heavy code cleaner and faster.
And you saw two handy patterns: the enum singleton and constant-specific methods. Reach for enums whenever a value has a small, fixed set of options. Your code will be safer and easier to read.