An enum (short for enumeration) is a data type whose values are a fixed set of named constants, such as the four directions EAST, WEST, NORTH and SOUTH. In Java, an enum is a special class declared with the enum keyword. Every Java enum constant is one object of that class, created once when the class is loaded, and every enum class extends java.lang.Enum.
We use an enum when we know all possible values of a variable at compile time or design time, such as order statuses, log levels, days of the week or compass directions. We can still add more values later as we identify them. The compiler rejects any value outside the set, so a method that takes a Direction parameter can never get “Est” or the number 7. This compile-time type safety is the main purpose of an enum.
The following example declares a Direction enum on Java 25 and uses the operations this tutorial covers, each line with its result as a comment.
enum Direction { EAST, WEST, NORTH, SOUTH }
Direction dir = Direction.NORTH; // NORTH
Direction[] all = Direction.values(); // [EAST, WEST, NORTH, SOUTH]
Direction east = Direction.valueOf("EAST"); // EAST
String name = dir.name(); // "NORTH"
int position = dir.ordinal(); // 2
boolean same = east == Direction.EAST; // true
String axis = switch (dir) { // "vertical"
case EAST, WEST -> "horizontal";
case NORTH, SOUTH -> "vertical";
};
Direction bad = Direction.valueOf("up"); // IllegalArgumentException
Notice that values() returns the constants in declaration order, the ordinal starts at 0, and == works because each constant exists only once. Also notice that valueOf() throws for a name that doesn’t exist. In the rest of this tutorial, we build on this enum.
- We add fields, a constructor and methods to Direction, and give each constant its own behavior.
- We convert a String to an enum without exceptions.
- We use enums in switch expressions and pattern matching, EnumSet and EnumMap, singletons and JSON.
1. What Is an Enum in Java?
Enumerated types are a set of related constants, and languages such as C and C++ have had them from the beginning. Java added them in JDK 1.5 (Java 5) with the enum keyword. A Java enum is more than a list of names, because it is a full class that always extends java.lang.Enum. So a constant can carry its own fields and methods.
Before Java 5, developers wrote a group of int constants instead. With int constants, the compiler sees only numbers, so it can neither reject a wrong value nor print a name.
| Concern | public static final int EAST = 0; | enum Direction { EAST, … } |
|---|---|---|
| Type safety | Any int compiles, such as move(42) | Only Direction constants compile |
| Printing | Prints 0 | Prints EAST |
| List all values | Not possible without extra code | Direction.values() |
| Extra data and behavior | Separate arrays or maps | Fields and methods on each constant |
| switch without default | Never exhaustive | Exhaustive when every constant is covered |
| Namespace | EAST can clash with other constants | Always qualified as Direction.EAST |
1.1. The enum Keyword Is Reserved
The enum word is one of the reserved keywords in Java, which means we cannot use it as a variable, method or class name. For example, the following line does not compile.
String enum = "Hello World !!";
The javac compiler reports “as of release 5, ‘enum’ is a keyword, and may not be used as an identifier”, whereas the Eclipse IDE shows a syntax error in the editor.

1.2. How the Compiler Sees an Enum
Logically, each enum constant is an instance of the enum type itself. When we compile an enum whose constants have no class body, javac generates a final class that extends Enum, one public static final field per constant, a private constructor, and the static methods values() and valueOf(). Running javap -p on the compiled Direction class from section 6 shows this generated code.
public final class com.howtodoinjava.core.enums.Direction extends java.lang.Enum<com.howtodoinjava.core.enums.Direction> {
public static final com.howtodoinjava.core.enums.Direction EAST;
public static final com.howtodoinjava.core.enums.Direction WEST;
public static final com.howtodoinjava.core.enums.Direction NORTH;
public static final com.howtodoinjava.core.enums.Direction SOUTH;
private static final com.howtodoinjava.core.enums.Direction[] $VALUES;
public static com.howtodoinjava.core.enums.Direction[] values();
public static com.howtodoinjava.core.enums.Direction valueOf(java.lang.String);
private com.howtodoinjava.core.enums.Direction(int, java.lang.String);
...
}
The JVM creates the four objects once, in the static initializer of the class, and never again. Each object gets its name and ordinal from Enum, plus the fields we declare.

1.3. Naming Conventions
Enum constants are constants, so we write them in UPPER_CASE letters like other Java constants. The same naming conventions apply to enums.
- The enum name is in title case, the same as class names, e.g. Direction or OrderStatus.
- The constants are in all upper case with underscores, the same as static final constants, e.g. NORTH or OUT_OF_STOCK.
2. Declaring and Using a Java Enum
We can declare an enum as a top-level type in its own file, or nested inside a class. A nested enum is implicitly static, so we refer to it as Robot.Mode without an instance of Robot. When the enum has only constants, the semicolon after the last constant is optional.
// Direction.java, top-level
public enum Direction {
EAST, WEST, NORTH, SOUTH
}
// Nested in a class, implicitly static
public class Robot {
enum Mode { MANUAL, AUTO }
}
We create a variable of an enum type the same way we use final static class fields. The variable holds one of the constants, or null.
Direction north = Direction.NORTH; // NORTH
String text = north.toString(); // "NORTH"
3. Built-in Methods values(), valueOf(), name() and ordinal()
Every enum gets two static methods from the compiler, values() and valueOf(String), and inherits the instance methods of Enum. Most inherited methods are final, so only toString() can be overridden. The results are for the Direction enum.
| Method | What it returns | Example | Result |
|---|---|---|---|
| values() | A new array with all constants in declaration order | Direction.values() | [EAST, WEST, NORTH, SOUTH] |
| valueOf(String) | The constant with this name, case-sensitive | Direction.valueOf(“EAST”) | EAST |
| name() | The constant name as declared (final method) | Direction.NORTH.name() | “NORTH” |
| toString() | The name, unless the enum overrides it | Direction.NORTH.toString() | “NORTH” |
| ordinal() | The zero-based position in the declaration | Direction.NORTH.ordinal() | 2 |
| compareTo(E) | Negative, zero or positive by declaration order | Direction.EAST.compareTo(Direction.NORTH) | -2 |
| getDeclaringClass() | The enum class, also for constants with a body | Direction.SOUTH.getDeclaringClass() | Direction |
| Enum.valueOf(Class, String) | The generic form of valueOf() | Enum.valueOf(Direction.class, “WEST”) | WEST |
3.1. The ordinal() Method
The ordinal() method returns the order of an enum instance among the list of constants. It represents the sequence in the enum declaration, where the initial constant is assigned an ordinal of 0, much like array indices.
The ordinal is designed for enum-based data structures, such as EnumSet and EnumMap. We never store an ordinal in a database or a file, because inserting a new constant in the middle of the enum shifts every ordinal after it. We store name() or a field of our own instead.
int eastOrdinal = Direction.EAST.ordinal(); // 0
int northOrdinal = Direction.NORTH.ordinal(); // 2
int order = Direction.EAST.compareTo(Direction.NORTH); // -2
3.2. The values() and valueOf() Methods
The values() method returns all the enum constants as an array, so we use it to loop over an enum. It returns a new copy of the array on each call, which keeps the internal array safe from changes.
for (Direction direction : Direction.values()) {
System.out.println(direction.ordinal() + " " + direction.name());
}
The loop prints the ordinal and the name of each constant.
0 EAST
1 WEST
2 NORTH
3 SOUTH
The valueOf() method converts a string to an enum instance. It accepts only the exact constant name, as we will see in section 4.
Direction east = Direction.valueOf("EAST"); // EAST
Direction viaClass = Enum.valueOf(Direction.class, "WEST"); // WEST
3.3. Difference Between name() and toString()
Both methods return the constant name by default. The difference is that name() is final, whereas toString() can be overridden to return a display text. Since valueOf() matches name(), an overridden toString() does not work as input for valueOf().
// enum Size { SMALL, LARGE; toString() returns name().toLowerCase() }
String text = Size.LARGE.toString(); // "large"
String name = Size.LARGE.name(); // "LARGE"
Size size = Size.valueOf("large"); // IllegalArgumentException
4. Converting a String to an Enum Safely
Strings that come from a user, a URL parameter, a config file or a CSV column rarely match a constant name character by character. The valueOf() method either returns the constant or throws an exception, and it throws two different ones.
- It throws IllegalArgumentException when no constant has this exact name, including different case or extra blanks.
- It throws NullPointerException with the message “Name is null” when the input is null.
Direction lower = Direction.valueOf("east"); // IllegalArgumentException: No enum constant com.howtodoinjava.core.enums.Direction.east
Direction missing = Direction.valueOf(null); // NullPointerException: Name is null
The safe version is a static lookup method on the enum that returns an Optional. It strips blanks, ignores case and never throws, so the caller decides what an unknown value means.
public static Optional<Direction> fromName(String name) {
if (name == null) {
return Optional.empty();
}
String key = name.strip();
return Arrays.stream(values())
.filter(direction -> direction.name().equalsIgnoreCase(key))
.findFirst();
}
The caller gets an Optional and picks a default, or rejects the input with a clear message.
Optional<Direction> found = Direction.fromName(" east "); // Optional[EAST]
Optional<Direction> unknown = Direction.fromName("up"); // Optional.empty
Optional<Direction> noInput = Direction.fromName(null); // Optional.empty
Direction direction = Direction.fromName("up").orElse(Direction.NORTH); // NORTH

When the input is not the constant name but another value, such as a code or a URL, we look it up through a field, as shown in section 6.3 and in Java enum with strings.
5. Using an Enum in a Switch
An enum is a natural fit for a switch, because the compiler knows every possible constant. Inside the case labels, we write the constant name without the enum type, such as case EAST. Java 21 and later also accept the qualified name case Direction.EAST, which older versions reject. Java offers three styles, and the newer ones catch more mistakes at compile time.
5.1. Classic switch Statement
The classic switch statement uses case …: labels and needs a break after each branch. The compiler does not check that every constant is handled, so we add a default branch that throws for an unexpected value.
String axis;
switch (direction) {
case EAST:
case WEST:
axis = "horizontal";
break;
case NORTH:
case SOUTH:
axis = "vertical";
break;
default:
throw new IllegalStateException("Unknown direction: " + direction);
}
5.2. Arrow switch Expression
Since Java 14, a switch expression with arrow labels returns a value and has no fall-through. When the cases cover every constant, we leave out default, and the compiler checks the coverage for us.
String label = switch (direction) {
case EAST, WEST -> "horizontal";
case NORTH, SOUTH -> "vertical";
};
If we remove the NORTH, SOUTH line, the code no longer compiles.
error: the switch expression does not cover all possible input values
So a switch expression without default turns “we added a new constant and forgot a case” into a compile error. If a new constant is added and only the enum is recompiled, the old switch code throws MatchException at runtime (Java 21 and later).
5.3. Pattern Matching for switch on Java 25
Pattern matching for switch, final since Java 21, adds two features that help with enums. A case null label handles a null selector, which otherwise throws NullPointerException. A guarded pattern such as case Direction d when … matches constants by a condition on their fields.
String text = switch (direction) {
case null -> "no direction";
case EAST -> "sunrise side";
case Direction d when d.getAngle() > 180 -> d.name() + " is past 180 degrees";
case Direction d -> d.name() + " at " + d.getAngle() + " degrees";
};
For each constant and for null, the method returns the following text.
sunrise side
WEST at 180 degrees
NORTH at 90 degrees
SOUTH is past 180 degrees
no direction
The cases are checked from top to bottom, so EAST matches its own label first. The last case Direction d catches all remaining constants, which keeps the switch exhaustive. We cover more patterns in record patterns and pattern matching.
6. Enum Fields, Constructors and Methods
An enum is a special class, so it can have fields, constructors, methods and nested types like any other class. We add them after the list of constants, and in that case the semicolon after the last constant is required.
6.1. Java Enum Constructor
By default, enums don’t require a constructor, and the value of each constant is the name used in the declaration. We define our own constructor to give each constant its own state. For example, every direction has an angle, so we pass it in parentheses after each constant name.
public enum Direction {
EAST(0, "E"), WEST(180, "W"), NORTH(90, "N"), SOUTH(270, "S");
private final int angle;
private final String abbreviation;
// Enum constructors are always private
Direction(int angle, String abbreviation) {
this.angle = angle;
this.abbreviation = abbreviation;
}
public int getAngle() {
return angle;
}
public String getAbbreviation() {
return abbreviation;
}
}
A Java enum constructor follows a few rules that differ from regular classes.
- The constructor is implicitly private. Declaring it public or protected is a compile-time error.
- We cannot call it ourselves. The code new Direction() fails with “enum classes may not be instantiated”.
- The JVM calls it once per constant when the class is loaded, in declaration order.
- It cannot read a non-constant static field of the same enum, because static fields are initialized after the constants. The compiler reports “illegal reference to static field from initializer”.
We read the state with a regular method call on the constant.
Direction west = Direction.WEST;
int angle = west.getAngle(); // 180
String abbreviation = west.getAbbreviation(); // "W"
6.2. Custom Methods
Adding a concrete method to an enum is similar to adding it to any other class. We can use any access modifier and return values from enum methods, or use them for internal logic. Inside the method, this is the current constant.
public String message() {
String message = "Moving in " + this + " direction";
return message;
}
String message = Direction.NORTH.message(); // "Moving in NORTH direction"
6.3. Enum With Multiple Values
Each constant can carry several values, e.g. an angle and an abbreviation. To find a constant by one of these values (a reverse lookup), we build a Map once in a static field. The map is created after all constants exist, so it can call values().
private static final Map<String, Direction> BY_ABBREVIATION = Arrays.stream(values())
.collect(Collectors.toUnmodifiableMap(Direction::getAbbreviation, Function.identity()));
public static Optional<Direction> fromAbbreviation(String abbreviation) {
if (abbreviation == null) {
return Optional.empty();
}
String key = abbreviation.strip().toUpperCase(Locale.ROOT);
return Optional.ofNullable(BY_ABBREVIATION.get(key));
}
Optional<Direction> byCode = Direction.fromAbbreviation("s"); // Optional[SOUTH]
Optional<Direction> byAngle = Direction.fromAngle(450); // Optional[NORTH]
The fromAngle() method in the example code uses Math.floorMod(), so 450 and -270 both return NORTH. More variations are in Java enum with multiple values.
7. Abstract Methods per Constant
We can also add abstract methods to an enum. In that case, each constant must implement the abstract method in its own class body. We use constant-specific bodies when the constants differ in logic, not only in data. When they differ only in data, a constructor field as in section 6.1 is simpler.
The following example is a Turn enum whose constants change a Direction. LEFT turns 90 degrees counterclockwise, RIGHT turns 90 degrees clockwise and BACK turns around.
public enum Turn {
LEFT {
@Override
public Direction apply(Direction current) {
return rotate(current, 90);
}
},
RIGHT {
@Override
public Direction apply(Direction current) {
return rotate(current, -90);
}
},
BACK {
@Override
public Direction apply(Direction current) {
return rotate(current, 180);
}
};
// Every constant must implement this method
public abstract Direction apply(Direction current);
private static Direction rotate(Direction current, int degrees) {
return Direction.fromAngle(current.getAngle() + degrees).orElseThrow();
}
}
If a constant leaves out apply(), the enum does not compile, so the abstract method works as a contract (a template) for every constant, including ones added later.
Direction afterLeft = Turn.LEFT.apply(Direction.EAST); // NORTH
Direction afterRight = Turn.RIGHT.apply(Direction.EAST); // SOUTH
Direction afterBack = Turn.BACK.apply(Direction.NORTH); // SOUTH
Each constant with a body compiles to its own anonymous subclass, e.g. Turn$1, and the enum class becomes sealed to those subclasses. That is why we call getDeclaringClass() instead of getClass() to get Turn.
8. Enum Inheritance and Interfaces
Every enum extends java.lang.Enum, an abstract class that is the common base class of all Java enumeration types.
public abstract class Enum<E extends Enum<E>>
implements Constable, Comparable<E>, Serializable {
// ...
}
The declaration means that all enums are comparable and serializable implicitly. As all enums extend java.lang.Enum, an enum cannot extend any other class, because Java does not support multiple inheritance of classes. The code enum Turn extends Base fails to compile.
But enums can implement any number of interfaces. For example, Turn takes a Direction and returns a Direction, which is the functional interface UnaryOperator<Direction>. We add it to the declaration, and the constant bodies from section 7 already implement its apply() method.
public enum Turn implements UnaryOperator<Direction> {
// LEFT, RIGHT and BACK as before
}
Function<Direction, Direction> twoLefts = Turn.LEFT.andThen(Turn.LEFT);
Direction result = twoLefts.apply(Direction.EAST); // WEST
We can pass a Turn constant anywhere a UnaryOperator<Direction> is expected, and Turn inherits the default method andThen() from Function. An interface also lets several enums share one type, which is the usual workaround for “enums cannot extend each other”.
9. EnumSet and EnumMap
The java.util package has two collections designed for enums. EnumSet is a Set implementation for enum elements, and EnumMap is a Map implementation for enum keys. All elements or keys must come from a single enum type, specified explicitly or implicitly when the collection is created.
Both use the ordinal as an index. An EnumSet is a bit vector, stored in one long for enums with up to 64 constants, and an EnumMap is an array with one slot per constant. So both are faster and smaller than HashSet and HashMap, and both iterate in declaration order.

9.1. EnumSet
We create an EnumSet with static factory methods rather than a constructor. The factory methods cover the common cases, such as a set of a few constants, all constants, a range or the complement of another set.
Set<Direction> horizontal = EnumSet.of(Direction.WEST, Direction.EAST); // [EAST, WEST]
Set<Direction> vertical = EnumSet.complementOf(EnumSet.copyOf(horizontal)); // [NORTH, SOUTH]
Set<Direction> all = EnumSet.allOf(Direction.class); // [EAST, WEST, NORTH, SOUTH]
Set<Direction> none = EnumSet.noneOf(Direction.class); // []
Set<Direction> range = EnumSet.range(Direction.WEST, Direction.SOUTH); // [WEST, NORTH, SOUTH]
boolean hasNorth = vertical.contains(Direction.NORTH); // true
Notice that EnumSet.of(WEST, EAST) prints [EAST, WEST], because the set always follows the declaration order. EnumSet does not permit null elements, so add(null) throws NullPointerException. Like most collection implementations, EnumSet is not synchronized, so when several threads modify one set, we wrap it with Collections.synchronizedSet().
9.2. EnumMap
An EnumMap takes the enum class in its constructor. Like EnumSet, it does not permit null keys (values may be null) and it is not synchronized.
Map<Direction, Integer> steps = new EnumMap<>(Direction.class);
steps.put(Direction.SOUTH, 2);
steps.put(Direction.EAST, 5);
steps.merge(Direction.EAST, 1, Integer::sum); // EAST=6
int northSteps = steps.getOrDefault(Direction.NORTH, 0); // 0
String printed = steps.toString(); // {EAST=6, SOUTH=2}
We use EnumMap whenever the keys are enum constants, e.g. a count per status or a handler per event type. The Java EnumMap tutorial covers its methods in detail.
10. Comparing Enums With == vs equals()
Each enum constant is a singleton, which means the JVM holds one object per constant. Because of that, we can compare constants with the equals() method or with the == operator, and both return the same result for two non-null constants.
Direction east = Direction.EAST;
Direction eastNew = Direction.valueOf("EAST");
Direction nothing = null;
boolean same = east == eastNew; // true
boolean equal = east.equals(eastNew); // true
boolean nullSafe = nothing == Direction.EAST; // false
boolean otherType = Direction.EAST.equals(Turn.LEFT); // false, compiles
boolean crash = nothing.equals(Direction.EAST); // NullPointerException
We prefer == for enums, because it never throws NullPointerException and the compiler checks the types. The code Direction.EAST == Turn.LEFT fails with “incomparable types: Direction and Turn”, whereas equals() compiles and returns false. The equals() and hashCode() methods of Enum are final and use identity, so no enum can change that behavior.
To sort or order constants, we use compareTo(), which compares by declaration order, as we saw in section 3.1.
11. Enum Singleton
An enum with a single constant is the simplest way to write a singleton in Java. The JVM creates the constant once, in a thread-safe way, when the class is loaded. Java serialization returns the same constant on deserialization, and reflection cannot create a second one.
public enum PathUtils {
INSTANCE;
private final Path rootPath;
PathUtils() {
rootPath = Paths.get("");
}
public static PathUtils getInstance() {
return INSTANCE;
}
public Path getRootPath() {
return rootPath;
}
}
PathUtils first = PathUtils.getInstance();
boolean sameInstance = first == PathUtils.INSTANCE; // true
A call to Constructor.newInstance() on an enum throws IllegalArgumentException with the message “Cannot reflectively create enum objects”. The trade-offs are that the instance cannot be created lazily on first use, and the singleton cannot extend another class. We compare enum singletons with the other singleton styles in a separate article.
12. Enum Serialization and JSON
Enums get special treatment in both Java serialization and JSON libraries. In both cases, the constant name is what gets written by default, not the field values.
12.1. Java Serialization
The Java serialization specification writes only the name of an enum constant. On reading, it calls valueOf() with that name, so we get the same constant object back. Field values are not written, and for enums the serialVersionUID and custom writeObject() or readObject() methods are ignored.
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(bytes)) {
out.writeObject(Direction.NORTH);
}
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
Direction restored = (Direction) in.readObject();
boolean sameConstant = restored == Direction.NORTH; // true
}
If a constant is renamed or removed, reading old data fails with InvalidObjectException, so we treat constant names as part of the stored format.
12.2. Enums in JSON With Jackson
Jackson 2.x writes an enum as its name() and reads it back with the same name. To use a different value, we annotate a getter with @JsonValue, and Jackson uses it in both directions. The following example uses Jackson 2.22.3 with a Move record that holds a Direction, and a CupSize enum with a @JsonValue code.
// enum CupSize { SMALL("S"), LARGE("L"), @JsonEnumDefaultValue UNKNOWN("?"); @JsonValue getCode() }
JsonMapper mapper = JsonMapper.builder().build();
String json = mapper.writeValueAsString(new Move(Direction.NORTH, 3)); // {"direction":"NORTH","steps":3}
Move move = mapper.readValue(json, Move.class); // Move[direction=NORTH, steps=3]
String sizeJson = mapper.writeValueAsString(CupSize.LARGE); // "L"
CupSize size = mapper.readValue("\"S\"", CupSize.class); // SMALL
Direction bad = mapper.readValue("\"UP\"", Direction.class); // InvalidFormatException
An unknown value fails with InvalidFormatException and lists the accepted values.
Cannot deserialize value of type `com.howtodoinjava.core.enums.Direction` from String "UP": not one of the values accepted for Enum class: [NORTH, WEST, SOUTH, EAST]
For input from other systems, we mark a fallback constant with @JsonEnumDefaultValue and enable READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, so an unknown value maps to that constant instead of failing.
JsonMapper lenient = JsonMapper.builder()
.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)
.build();
CupSize fallback = lenient.readValue("\"XL\"", CupSize.class); // UNKNOWN
Jackson 3 changed the defaults of READ_ENUMS_USING_TO_STRING and WRITE_ENUMS_USING_TO_STRING to true. With Jackson 3.2.3, an enum that overrides toString() is written and read by its toString() value, not its name. The examples above give the same output on Jackson 3 because Direction doesn’t override toString(), and the enum features moved to tools.jackson.databind.cfg.EnumFeature.
13. Common Mistakes With Java Enums
Most enum bugs come from treating an enum like an int or a String, and many of them show up only after someone adds a new constant.
| Mistake | What goes wrong | Fix |
|---|---|---|
| Storing ordinal() in a database, or JPA @Enumerated with the default EnumType.ORDINAL | A new constant in the middle shifts the stored numbers to other constants | Store name() (EnumType.STRING) or an explicit code field |
| Calling valueOf() on user input | IllegalArgumentException for “east” or ” EAST”, NullPointerException for null | A safe lookup that returns Optional, as in section 4 |
| Overriding toString() and parsing it with valueOf() | valueOf() matches name() only, so it throws | A lookup method that matches the display text |
| A default branch in every switch | A new constant falls into default without a compile error | A switch expression without default, as in section 5.2 |
| Mutable fields in an enum | Each constant is a global singleton, so every thread sees every change | Make all enum fields private final |
| Calling values() in a hot loop | Each call copies the array | Cache the array in a private static final field and never hand it out |
| Comparing with nothing.equals(EAST) | NullPointerException when the variable is null | Compare with == |
| Reading a static field in the constructor | Compile error “illegal reference to static field from initializer” | Build lookup maps in a static field after the constants |
14. Java Enum FAQs
Most enum questions come down to one fact, namely that an enum is a class with a fixed set of instances.
14.1. What Does Enum Mean?
Enum is short for enumeration, which means a complete, ordered list of all possible values of something. In programming, an enum type is a data type with a fixed set of named values. In Java, the values are objects of an enum class, so they can have fields and methods.
14.2. What Is an Enum Type in Java?
An enum type is a class declared with the enum keyword whose only instances are the constants listed in its body. The compiler makes it a final subclass of java.lang.Enum (or a sealed one when constants have bodies), and no code can create more instances.
14.3. Is an Enum a Class in Java?
Yes. An enum is a special kind of class, so it can have fields, constructors, methods, nested types and interfaces. The differences are that it cannot extend another class, and only the JVM creates its instances, so new Direction() does not compile.
14.4. Can an Enum Have a Constructor in Java?
Yes. An enum can have constructors with any parameters, and each constant passes its arguments in parentheses, e.g. EAST(0, “E”). The constructor is always private, and the JVM calls it once per constant, as shown in section 6.1.
14.5. Can an Enum Extend Another Class?
No. Every enum already extends java.lang.Enum, and Java allows only one superclass. An enum can implement any number of interfaces instead, as shown in section 8.
14.6. Can an Enum Variable Be null?
Yes. An enum variable is a reference, so it can be null like any other object reference. A switch on a null enum throws NullPointerException unless it has a case null label (Java 21 and later), as in section 5.3.
14.7. Is an Enum the Same as Enumeration in Java?
No. An enum is a type with a fixed set of constants, whereas java.util.Enumeration is an old interface for looping over the elements of legacy collections such as Vector. The difference between Enumeration and Iterator explains that interface.
14.8. Are Java Enums Thread-Safe?
The constants themselves are created in a thread-safe way, because the JVM initializes the enum class only once. The fields of a constant are as thread-safe as we make them, so we keep them final and immutable.
15. Conclusion
A Java enum is a class with a fixed set of instances, one per constant. It gives us compile-time type safety and a built-in values() list, which plain int or String constants never had.
The built-in methods cover most needs. We use name() for storage and ordinal() only inside EnumSet and EnumMap. For strings from outside the app, a lookup that returns Optional is safer than valueOf(), which either returns the constant or throws.
Constructors, fields and methods turn constants into small objects with their own data, and abstract methods give each constant its own behavior. Switch expressions without default and pattern matching on Java 21 and later make the compiler check that every constant is handled. For single instances, an enum is the simplest thread-safe singleton.
16. References
- Enum Classes (Java Language Specification, Java SE 25)
- java.lang.Enum Javadoc (Java SE 25)
- EnumSet Javadoc and EnumMap Javadoc
- JEP 361: Switch Expressions
- JEP 441: Pattern Matching for switch
- Serialization of Enum Constants (Java Object Serialization Specification)
- Enums (dev.java)
Happy Learning !!
final class Direction extends Enum
{
public final static Direction EAST = new Direction();
public final static Direction WEST = new Direction();
public final static Direction NORTH = new Direction();
public final static Direction SOUTH = new Direction();
}
I don’t understand this. How can enums be self-referential?
Every declared new Direction() should AGAIN have 4 member variables, yet it has only one value.
As they say – “enum is a special type of class”.
Hi Lokesh,
I am always confuse with when to use enum class and when to use Constant class.
As you defined basic DIRECTION(enum) above which holds the definition of direction(EAST, WEST, NORTH, SOUTH).
Similarly I can create my Direction class(below) which have EAST,WEST,NORTH,SOUTH constants.
public class Direction { public static final String EAST = "East"; public static final String WEST = "West"; public static final String NORTH = "North"; public static final String SOUTH = "South"; }Please elaborate which approach is good and when should we use enum and when should we use Constant class.
Thanks
Hi,
The above works as well. But, it would difficult to list the enum declarations from above Class. Where as I can retrieve all enum declarations using EnumSet.allOf(Direction.class) as explained by Lokesh.
So, you could decide based on your requirement and usage.
Hello Praveen,
I think in any scenario where you want to restrict the number of values, then enum will be much better than constant String because:
1. With above approach you wont be able to restrict user until you validate first.
2. You can design your APIs in such a way that they work with enum and hence restrict values, as String can take any kind of value.
3. With enums you can use == for comparison which is also null safe as compared to equals.
4. Its very easy to extend you logic with enums. So, for example, you can easily extend enum to EAST to accept both “East” and “E” as valid values but this wont be straight forward with String.
5. You can extend enums with util methods and then use those util methods in code, so future changes will only need update to util methods without impacting the caller of your API.
Hope it clarifies a bit.
Regards
Vishal Sinha
please check your html page codings.. there are some html tags displayed between the java code..
Hi Lokesh,
Let’s say there is Color enum with RED, GREEN, YELLOW and there is class Marks with color enum as its property. When I fetch Marks object from database I always pass the List Of markDto object in the order RED, GREEN, YELLOW irrespective of its corresponding values. By saying Corresponding values I meant I don’t care which color’s value is High or low. All I want is to fix the order RED, GREEN, YELLOW. Because from database it doesn’t guarantee the order but I have send the list to UI layer with above mentioned order.
Please tell me how can I achieve it?
Obviously, the database doesn’t support the sorting so you have to implement your own mechanism.
1) Create a
Comparator <MarkDTO>2) Override
compare(MarkDTO o1, MarkDTO o2)method.3) Use
Collections.sort(marks, new ColorSorter());Refer: Comparable and Comparator
Hi Lokesh,
If in database table, a column is enum type for example ( `language_type` enum(‘ENGLISH’,’HINDI’) DEFAULT NULL), then how can we insert data in this column using java hibernate entity class. I mean what would be the data type in java class. It should java enum type or java string type. Can we just use java string type?
Overall great and informative post about enums. Please, correct:
enums extends java.lang.Enum
that it somebody knows the exact angle
public class EnumMap,V>
Done. Thanks for pointing out.
i have created an enum class, and have exposed an api to add certain objects to a tree map. this is handled in another class. so basically in my api i call this method to add the object.
the problem i am facing while trying to write junit test cases for this scenario.. i am not able to add multiple objects . its a creating a new list each time when i create a new object or i change some value in the existing object and send it again.
Can I see some code?
Are you able to post some code ? If we could see some code, I think it would be easier to definitively identify the problem, rather than guessing at what the problem could potentially be.
https://gist.github.com/discover
how to impliment this enum
Which enum?
Hi Lokesh,
I am always confused with the values() API of enum. I mean Enum class don’t have this API.
Java Docs says
“The compiler automatically adds some special methods when it creates an enum. For example, they have a static values method that returns an array containing all of the values of the enum in the order they are declared. This method is commonly used in combination with the for-each construct to iterate over the values of an enum type.”
I mean what you think what is the reason behind such a design, Why it was not designed simple rather then adding it by compiler
Himansu, This is really a very good question. Let me put my take on this approach.
Method values() is a static method which is added at instance level (i.e. each concrete enum). Where possibly we can add a static method such that it is available to all concrete instances without having reference in super class (i.e. Enum class)? Not possible by normal semantics of core java. Please remember that values() is not available for Enum class level.
I believe that it was the only way for java designers to add a static method to concrete instances of enum. What’s your thoughts?
Hi Lokesh,
i too have the similar thought on this, hope along with the javadoc in near future Oracle may release the doc with reason behind the design :)
nice article as usual you write….now i have clear concept of ENUM.thanks lokesh :)
I need to convert from one Enum to another Enum. Would an EnumMap be the best way ? If so, would I put this EnumMap in a 3rd Enum declaration ? Or where would I place the EnumMap ? In my main class ?
Sorry Nick, but I am unable to understand the context in question. Why will somebody convert from one enum to another? What’s usecase?
Thanks for helping Lokesh. Yes, an example would make the question more clear:
I need to convert from Material.X to InventoryType.X …But notice that not all types can be converted. Only about 13 of them can actually make the conversion. I was curious about what some of the different approaches would be to do it.
I used your EnumMap to do it (just haven’t been able to test it out yet). Here’s my class so far. This class handles the conversion: BaseType.java
Would you do it this way ? Or maybe do string manipulation? Or another way? Thanks!
To me, it looks good. Only thing, I will not make this public. Even if somebody need reference of it then return a readonly copy through some getter method.
public static EnumMap<Material, InventoryType> emap = new EnumMap(Material.class);The above link is broken. Here’s the new link: BaseType.java
It’s working beautifully in the production code. Thanks!
Sorry, I refactored the project yet again (which broke the link). This time, I refactored to default maven directory structure in order to use the /test/ folder to add any unit tests.
If anyone was curious about the code related to my question, here it is BaseType.java
awesome this gives a complete view.. thanks for this..
This is a brilliant pattern – I had never thought about doing reverse lookups on an enum, until now!!! Handy … :)
BTW, the code is missing a cast to “(Direction)” against the return value of static method “Direction get(int angle)”. However, rather than using that cast (Java 1 onwards), the better solution would be to make use of generics (Java 5 onwards), which is ideal because the “int” for the angle will be auto-boxed into the Integer type within the Map.
i.e. change this:
private static final Map lookup = new HashMap();
to this:
private static final Map lookup = new HashMap();
then the cast is not needed.
The submission tool is removing the less-than and greater-then symbols. sorry, nothing I can do:
Map lookup = new HashMap ();
You can first convert the symbols into < and >. Anyways, I got the idea.
Can you please remind me the command line argument to view the generated class out of the enum please?
I mean command line command. Without using jad ofcourse. I used it earlier but forgot.