Back to Blog
Java

Java Enum Declaration: Syntax and Practical Usage

java enum declaration: Learn the correct syntax for declaring Java enums, adding fields and methods, using them in switch statements, and avoiding common pitfalls.

JavaEnumSyntaxType SafetySwitch
Illustration of Java enum declaration showing a set of named constants with associated fields and methods.

In Java, an enum is a special class that represents a fixed set of constants. The java enum declaration syntax is straightforward, but the feature goes far beyond simple constant lists. This article covers the declaration syntax, how to attach behavior to constants, and the runtime characteristics that affect real-world code.

Basic Enum Declaration

The simplest form of an enum declaration uses the enum keyword followed by a name and a list of constants:

public enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }

Each constant is an instance of the enum type. By default, the constants are ordered by their ordinal value, starting from zero. The compiler generates a static values() method that returns an array of all constants, and a static valueOf(String) method that maps a name to the corresponding constant. These are part of the enum's implicit API.

The declaration above is equivalent to a class that extends java.lang.Enum and has private constructors. You cannot instantiate an enum with new; the constants are the only instances.

Adding Fields, Constructors, and Methods

Enums become more useful when you attach data and behavior to each constant. You can declare fields, a constructor, and methods just like in a regular class. The constructor must be private or package-private because enum instances are created only within the enum body.

public enum Planet { MERCURY(3.303e+23, 2.4397e6), VENUS(4.869e+24, 6.0518e6), EARTH(5.976e+24, 6.37814e6); private final double mass; // in kilograms private final double radius; // in meters Planet(double mass, double radius) { this.mass = mass; this.radius = radius; } public double surfaceGravity() { return 6.67300E-11 * mass / (radius * radius); } }

Each constant is constructed with the arguments you provide. The fields are final because the constants are immutable by design. This pattern is common for enums that carry configuration data, such as HTTP status codes, database connection settings, or state machine states.

Using Enums in Switch Statements

One of the most common uses of an enum is in a switch statement. The compiler checks that all cases are valid enum constants, so a typo is caught at compile time.

public String describe(Day day) { switch (day) { case MONDAY: return "Start of the work week"; case FRIDAY: return "End of the work week"; case SATURDAY: case SUNDAY: return "Weekend"; default: return "Midweek"; } }

The default branch is optional, but it is useful when you want to handle a future constant that you might add later. Without a default, the compiler will not warn you if you forget a case; it simply falls through. If you want exhaustive handling, you can omit default and rely on the compiler's switch exhaustiveness check, but that only works if the switch is used as an expression in Java 14 and later.

Enum Constants with Constant-Specific Class Bodies

Sometimes a single method implementation is not enough; each constant may need its own behavior. You can define a constant-specific class body by adding a block after the constant name. This allows you to override methods per constant.

public enum Operation { PLUS { public double apply(double x, double y) { return x + y; } }, MINUS { public double apply(double x, double y) { return x - y; } }, TIMES { public double apply(double x, double y) { return x * y; } }; public abstract double apply(double x, double y); }

Each constant is an anonymous subclass of the enum type. This is a powerful way to implement strategy patterns without a separate class hierarchy. However, it can make the enum harder to read if the bodies become large. In that case, consider moving the logic to a separate class or using a functional interface with a lambda, depending on your design.

Common Mistakes and Pitfalls

A frequent error is trying to compare enum constants with == when they come from different sources. In Java, == is safe for enum constants because they are singletons, but only if both references point to the same enum type. If you receive an enum value from an untrusted source, you should still use == after a null check, or use equals() if you want to be defensive.

Another mistake is adding mutable fields to an enum. Because enums are singletons, mutable state is shared across the entire JVM. If you store a non-final field, you risk thread-safety issues and unexpected behavior. Keep enum fields final and prefer immutable objects.

A third issue is relying on ordinal() to represent a business value. The ordinal is the position in the declaration order, which can change if you reorder constants. If you need a stable numeric value, store it in a field explicitly.

Runtime Behavior and Performance

Enums are compiled into regular Java classes with a static final array for the constants. The values() method returns a new array each time it is called, so iterating over it repeatedly creates garbage. If you need to iterate frequently, cache the array in a static field.

private static final Day[] DAYS = Day.values();

Enum constants are singletons, so == comparison is both fast and safe. The JVM can also optimize switch statements on enums using a lookup table, making them efficient for large enums.

Memory usage is minimal: each constant is an object, but the JVM stores them in the enum class's static fields. There is no per-instance overhead beyond the fields you define.

When to Use Enums vs Other Approaches

Enums are the right choice when you have a fixed set of values that is known at compile time and you want type safety. If the set of values can change at runtime, such as values from a database, enums are not suitable. In that case, a Set or Map with validation is more appropriate.

For a small set of related constants, an enum is clearer than a final class with static constants because it provides type safety and allows methods. If you need to attach behavior that varies per constant, enums are often better than a switch statement on a string constant because the behavior is encapsulated with the constant.

Maintainability and Compatibility

Adding a new constant to an enum can break code that relies on exhaustive switch statements or that uses ordinal() for persistence. To maintain compatibility, avoid using ordinal() for serialization or database mapping. Instead, store an explicit id field and use it for persistence.

When you add a constant, existing switch statements without a default will compile without error but will not handle the new constant. Consider adding a default branch that throws an exception or handles the unknown case explicitly.

Enums are also serializable by default, but the serialized form depends on the constant name. If you rename a constant, the serialized data becomes invalid. For long-term storage, use an explicit id field and a custom readResolve method if needed.

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