Back to Blog
Java

Java Enum name(): What It Returns and When to Use It

java enum name: Learn what Java's enum name() returns, how it differs from toString(), and when to use name() with valueOf() for reliable persistence and logging.

JavaEnumsSerializationPersistenceString Conversion
A Java enum constant represented as a labeled card with an arrow pointing to its name string, illustrating the name() method returning the declared identifier.

When you call name() on a Java enum constant, you get the exact identifier that appears in the source code. For a constant declared as SHIPPED, name() returns the string "SHIPPED". This method is part of java.lang.Enum and is declared final, which means you cannot override it in your own enum type. Understanding what java enum name returns, and how it relates to toString() and valueOf(), is essential for persistence, logging, and serialization code.

What the name() Method Returns

Every Java enum constant inherits a name() method from java.lang.Enum. The method returns the exact identifier used when the constant was declared. Consider this enum:

public enum OrderStatus { NEW, PROCESSING, SHIPPED, DELIVERED, CANCELLED }

Calling name() on any constant returns its declared identifier:

OrderStatus status = OrderStatus.SHIPPED; String label = status.name(); System.out.println(label); // SHIPPED

The returned string is not derived from anything at runtime. It is the literal source identifier, stored in the enum constant when the class is initialized. Because name() is declared final in java.lang.Enum, no enum type can override it. That makes the method predictable: the value you get from name() is always the compile-time identifier, regardless of how the enum is implemented.

This behavior is the foundation for the rest of the article. Once you understand what name() returns, the next question is how it differs from toString().

name() vs toString(): What Changes and What Does Not

By default, toString() returns the same value as name(). The default implementation of toString() in java.lang.Enum simply returns the result of name(). The difference is that toString() is not final, so an enum type can override it:

public enum OrderStatus { NEW, PROCESSING, SHIPPED, DELIVERED, CANCELLED; @Override public String toString() { return name().charAt(0) + name().substring(1).toLowerCase(); } }

With this override, OrderStatus.SHIPPED.toString() returns "Shipped", while OrderStatus.SHIPPED.name() still returns "SHIPPED".

The practical consequence: use name() when you need the exact constant identifier for persistence, logging, or protocol messages. Use toString() when you want a human-readable representation that may be customized. Mixing the two can cause subtle bugs, especially if code elsewhere assumes toString() equals name().

Reverse Lookup with valueOf()

The companion to name() is valueOf(String), which maps a name back to the constant:

OrderStatus status = OrderStatus.valueOf("SHIPPED");

This is the inverse of name() for the same enum type. The lookup is case-sensitive and requires the exact identifier. Passing an unknown name throws IllegalArgumentException:

OrderStatus status = OrderStatus.valueOf("shipped"); // IllegalArgumentException

Passing null throws NullPointerException. The generic form, Enum.valueOf(OrderStatus.class, "SHIPPED"), behaves the same way and is useful when the enum type is only known at runtime.

The symmetry between name() and valueOf() is important for serialization and deserialization: name() produces the string, valueOf() consumes it. The two methods are designed to work as a pair.

Using Enum Names in Persistence and Logging

Storing the enum name in a database column or a log line is a common pattern. The name is stable as long as the constant identifier remains unchanged in the source code. For example, persisting OrderStatus.SHIPPED as "SHIPPED" and reading it back with valueOf() works without any additional mapping code.

The stability has a boundary: renaming a constant changes its name. If you rename SHIPPED to IN_TRANSIT, previously stored "SHIPPED" values will no longer match any constant, and valueOf() will throw IllegalArgumentException. For data that must survive refactoring, an explicit stable identifier is safer:

public enum OrderStatus { NEW(1), PROCESSING(2), SHIPPED(3), DELIVERED(4), CANCELLED(5); private final int code; OrderStatus(int code) { this.code = code; } public int code() { return code; } }

Use the numeric code for database persistence and keep name() for logs and debugging output. This separates the human-readable identifier from the stable storage key.

Common Mistakes When Working with Enum Names

The most frequent error is assuming name() is case-insensitive. It is not. valueOf("shipped") fails even though "SHIPPED" works. If input arrives from user-facing forms or external systems, normalize it before calling valueOf():

OrderStatus status = OrderStatus.valueOf(input.toUpperCase());

Another mistake is relying on toString() when it has been overridden. Code that logs status.toString() may produce a different string than code that logs status.name(). When the exact identifier matters, call name() explicitly.

A third issue is catching the wrong exception. valueOf() throws IllegalArgumentException for an unknown name, but code that catches Exception broadly can hide the failure. Catch IllegalArgumentException specifically when you want to handle unknown input gracefully.

Runtime Cost and Allocation Behavior

Calling name() does not create a new string. The identifier is stored in the enum constant when the class is initialized, and name() returns that stored reference. Repeated calls return the same object, so there is no per-call allocation. This makes name() cheap enough for hot paths like logging every request or writing every event.

The reverse operation, valueOf(), performs a lookup by string. The JDK implementation maintains an internal map from names to constants for each enum class, built lazily on first use. After the map is built, lookups are constant-time on average. The first call on a given enum type pays the one-time cost of constructing the map.

These characteristics matter in production: if you serialize enum names at high volume, name() is the low-cost direction, while valueOf() is the slightly more expensive reverse direction. Neither operation should be a bottleneck in ordinary application code.

When a Custom Mapping Is Better Than name()

There are cases where name() is not the right tool. If the external representation of an enum value must not change even when the constant is renamed, a custom mapping is safer. The numeric code example above is one option. Another is a dedicated string field:

public enum OrderStatus { NEW("new"), PROCESSING("processing"), SHIPPED("shipped"), DELIVERED("delivered"), CANCELLED("cancelled"); private final String key; OrderStatus(String key) { this.key = key; } public String key() { return key; } }

This decouples the persistence key from the Java identifier. You can rename PROCESSING to IN_PROGRESS without breaking stored data, because the key "processing" remains unchanged.

The tradeoff is that you now maintain two representations instead of one. Choose name() when the identifier is stable and the enum is internal to your application. Choose a custom mapping when the value crosses a system boundary, such as a database, an API payload, or a configuration file that other teams or services depend on.

java enum name: Practical Usage and Code Examples | RYUSLOG DEV