Enum in Java – Type-Safe Constants with Behaviour
An enum (enumeration) is a special class that represents a fixed set of named constants, such as the days of the week, order statuses or planets. Declared with the enum keyword, Java enums are far more powerful than integer constants: they are type-safe, have names, can hold fields and methods, and work naturally with switch.
This tutorial covers the built-in enum methods, enums in switch, fields and constructors, constant-specific behaviour, interfaces, EnumSet and EnumMap, and the enum singleton.
1. Declaring and Using an Enum
public class EnumBasics {
enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
public static void main(String[] args) {
Day today = Day.FRIDAY;
System.out.println("today = " + today);
System.out.println("name() = " + today.name());
System.out.println("ordinal() = " + today.ordinal());
System.out.println("valueOf(\"SUNDAY\") = " + Day.valueOf("SUNDAY"));
System.out.println("compareTo(MONDAY) = " + today.compareTo(Day.MONDAY));
System.out.println("== comparison = " + (today == Day.FRIDAY));
System.out.print("values() = ");
for (Day d : Day.values()) System.out.print(d.name().substring(0, 3) + " ");
System.out.println();
try {
Day.valueOf("FUNDAY");
} catch (IllegalArgumentException e) {
System.out.println("valueOf(\"FUNDAY\") -> IllegalArgumentException");
}
}
}
today = FRIDAY
name() = FRIDAY
ordinal() = 4
valueOf("SUNDAY") = SUNDAY
compareTo(MONDAY) = 4
== comparison = true
values() = MON TUE WED THU FRI SAT SUN
valueOf("FUNDAY") -> IllegalArgumentException
| Method | Returns |
|---|---|
values() | Array of all constants, in declaration order |
valueOf(String) | The constant with that exact name, or IllegalArgumentException |
name() | The constant's declared name |
ordinal() | Zero-based position in the declaration |
compareTo() | Comparison by ordinal (enums are Comparable) |
Each constant is a single object, so enums can be compared safely with ==.
2. Why Enums Instead of int Constants?
// int constants: no type safety
static final int PLACED = 0, SHIPPED = 1;
static final int RED = 0;
void setStatus(int status) { ... }
setStatus(RED); // compiles! Any int is accepted, and it prints as "0"
// enums: checked by the compiler
enum Status { PLACED, SHIPPED }
enum Color { RED, GREEN }
void setStatus(Status status) { ... }
setStatus(Color.RED); // compile error: incompatible types
- Type safety: only valid constants of the right enum are accepted.
- Readable output:
toString()prints the name, not a number. - Namespace: constants are qualified by their type (
Status.SHIPPED). - Behaviour: enums can have fields, methods and constructors.
3. Enums in switch
Switch expressions over enums are exhaustive: if you cover every constant, no default is needed, and the compiler reports an error when a new constant is added but not handled:
public class EnumSwitch {
enum OrderStatus { PLACED, PACKED, SHIPPED, DELIVERED, CANCELLED }
static String message(OrderStatus s) {
return switch (s) { // exhaustive: no default needed
case PLACED -> "We have received your order";
case PACKED -> "Your order is packed";
case SHIPPED -> "Your order is on the way";
case DELIVERED -> "Delivered. Enjoy!";
case CANCELLED -> "Your order was cancelled";
};
}
public static void main(String[] args) {
for (OrderStatus s : OrderStatus.values())
System.out.printf("%-9s : %s%n", s, message(s));
}
}
PLACED : We have received your order PACKED : Your order is packed SHIPPED : Your order is on the way DELIVERED : Delivered. Enjoy! CANCELLED : Your order was cancelled
4. Fields, Constructors and Methods
Constants can carry data passed to a constructor, which is implicitly private:
public class EnumWithFields {
enum Planet {
MERCURY(3.303e+23, 2.4397e6),
EARTH(5.976e+24, 6.37814e6),
JUPITER(1.9e+27, 7.1492e7);
private static final double G = 6.67300E-11;
private final double mass; // kg
private final double radius; // m
Planet(double mass, double radius) { // constructor is implicitly private
this.mass = mass;
this.radius = radius;
}
double surfaceGravity() { return G * mass / (radius * radius); }
double weightOf(double earthWeight) { return earthWeight / EARTH.surfaceGravity() * surfaceGravity(); }
}
public static void main(String[] args) {
double kg = 70;
for (Planet p : Planet.values())
System.out.printf("A %.0f kg person weighs like %6.1f kg on %s%n", kg, p.weightOf(kg), p);
}
}
A 70 kg person weighs like 26.4 kg on MERCURY A 70 kg person weighs like 70.0 kg on EARTH A 70 kg person weighs like 177.1 kg on JUPITER
5. Constant-Specific Behaviour and Interfaces
Each constant can provide its own implementation of an abstract method, and an enum can implement interfaces:
public class EnumAbstractMethods {
// Constant-specific behaviour: each constant overrides an abstract method
enum Operation {
PLUS("+") { int apply(int a, int b) { return a + b; } },
MINUS("-") { int apply(int a, int b) { return a - b; } },
TIMES("*") { int apply(int a, int b) { return a * b; } };
private final String symbol;
Operation(String symbol) { this.symbol = symbol; }
abstract int apply(int a, int b);
@Override public String toString() { return symbol; }
}
// Enums can implement interfaces too
interface PriceRule { int finalPrice(int price); }
enum Discount implements PriceRule {
NONE, STUDENT, SENIOR;
public int finalPrice(int price) {
return switch (this) { case NONE -> price; case STUDENT -> price * 80 / 100; case SENIOR -> price / 2; };
}
}
public static void main(String[] args) {
for (Operation op : Operation.values())
System.out.println("8 " + op + " 3 = " + op.apply(8, 3));
for (Discount d : Discount.values())
System.out.println(d + " pays " + d.finalPrice(500));
}
}
8 + 3 = 11 8 - 3 = 5 8 * 3 = 24 NONE pays 500 STUDENT pays 400 SENIOR pays 250
This replaces long if-else chains with polymorphism: adding a new Operation forces you to implement apply.
6. EnumSet and EnumMap
These specialised collections are backed by bit vectors and arrays, making them extremely fast and compact:
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
public class EnumCollections {
enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
public static void main(String[] args) {
EnumSet<Day> weekend = EnumSet.of(Day.SAT, Day.SUN);
EnumSet<Day> weekdays = EnumSet.complementOf(weekend);
EnumSet<Day> midweek = EnumSet.range(Day.TUE, Day.THU);
System.out.println("weekend: " + weekend);
System.out.println("weekdays: " + weekdays);
System.out.println("midweek: " + midweek);
Map<Day, Integer> hours = new EnumMap<>(Day.class); // kept in declaration order
hours.put(Day.WED, 8); hours.put(Day.MON, 9); hours.put(Day.FRI, 6);
System.out.println("hours: " + hours);
}
}
weekend: [SAT, SUN]
weekdays: [MON, TUE, WED, THU, FRI]
midweek: [TUE, WED, THU]
hours: {MON=9, WED=8, FRI=6}
7. Enum Singleton
A single-constant enum is the simplest way to implement a singleton. The JVM guarantees one instance, thread-safe initialisation, and protection against reflection and serialization creating copies:
public class EnumSingleton {
// The simplest thread-safe, serialization-safe singleton
enum AppConfig {
INSTANCE;
private String env = "dev";
String env() { return env; }
void setEnv(String env) { this.env = env; }
}
public static void main(String[] args) {
AppConfig.INSTANCE.setEnv("production");
System.out.println("env = " + AppConfig.INSTANCE.env());
System.out.println("same instance: " + (AppConfig.INSTANCE == AppConfig.valueOf("INSTANCE")));
}
}
env = production same instance: true
8. Rules and Facts
- Every enum implicitly extends
java.lang.Enum, so it cannot extend another class; it can implement interfaces. - Enums are implicitly
final(unless constants have bodies) and cannot be instantiated withnew. - Constants must be listed first; fields and methods follow after a semicolon.
- Constructors are always private (or package-private), never public.
- Enums are
SerializableandComparable; serialization stores only the name. - Do not persist
ordinal()values (for example in databases): reordering constants changes them. Store the name instead.
9. Summary
- An enum defines a fixed set of type-safe constants.
- Use
values(),valueOf(),name()andordinal(); compare with==. - Enums can have fields, constructors, methods, constant-specific bodies and implement interfaces.
- Use them in exhaustive switch expressions, and with
EnumSetandEnumMap. - A single-element enum is the best singleton.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is an enum in Java?
A special class type that defines a fixed set of named constants, introduced in Java 5.
Q2. Can an enum have a constructor?
Yes, but it is always private (implicitly), and it runs once for each constant when the enum class is initialised.
Q3. Can an enum extend a class?
No. Every enum implicitly extends java.lang.Enum, and Java allows only one superclass.
Q4. Can an enum implement an interface?
Yes, any number of interfaces.
Q5. Can I create an enum object with new?
No. The only instances are the declared constants.
Q6. Should I compare enums with == or equals()?
Either works, but == is preferred: it is null-safe and checked at compile time for type compatibility.
Q7. What does values() return?
A new array containing all the enum's constants in declaration order.
Q8. What happens if valueOf() gets an unknown name?
It throws IllegalArgumentException. The name must match exactly, including case.
Q9. What is ordinal()?
The zero-based position of a constant in the enum declaration. Avoid relying on it for persistence or logic.
Q10. Can enums have abstract methods?
Yes. Each constant must then provide a body implementing them.
Q11. Can enums be used in switch statements?
Yes. Case labels use the constant names without the type prefix, and switch expressions can be exhaustive without a default.
Q12. What is EnumSet?
A high-performance Set implementation for enum types, stored internally as a bit vector.
Q13. What is EnumMap?
A Map with enum keys, stored as an array indexed by ordinal and iterated in declaration order.
Q14. Why is an enum singleton recommended?
The JVM guarantees a single instance and thread-safe creation, and enums cannot be cloned or duplicated by reflection or deserialization.
Q15. Can an enum have a main method?
Yes. Enums can have static methods, including main.
Q16. Are enums serializable?
Yes. Only the constant's name is written, and deserialization returns the existing constant.
Q17. Can an enum be nested inside a class?
Yes. Nested enums are implicitly static.
Q18. What is the difference between name() and toString()?
name() always returns the declared name and is final. toString() returns the name by default but can be overridden for display text.
Q19. Can an enum be generic?
No. Enum declarations cannot have type parameters, although they can implement generic interfaces.
Q20. How do I store enums in a database?
Store the name (for example JPA @Enumerated(EnumType.STRING)) rather than the ordinal, so reordering constants does not corrupt data.