Introduction
Imagine you're building a traffic light system. The light can only be in one of three states: RED, YELLOW, or GREEN. You could use strings like "red", "yellow", "green", but what if someone misspells "gren" or uses "blue"? Enum types in Java solve this problem perfectly—they allow you to define a fixed set of constants that are type-safe and self-documenting.
Enums (short for enumerations) are special Java types that represent a fixed set of constants. They're like classes but with a predefined set of instances. Think of them as pre-made objects that you can choose from!
What are Enum Types?
Enum types are special data types that enable a variable to be a set of predefined constants. The variable must equal one of the values that have been predefined for it.
Key Characteristics:
- ✅ Type-safe - Compiler checks for valid values
- ✅ Fixed set of instances - Predefined constants
- ✅ Can have fields, methods, and constructors - Like classes
- ✅ Implicitly final - Cannot be extended
- ✅ Implicitly extends java.lang.Enum - Automatic inheritance
Code Explanation with Examples
Example 1: Basic Enum Declaration
// ✅ BASIC ENUM DECLARATION
// Simple enum with just constant names
enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}
// Enum with simple behavior
enum TrafficLight {
RED, YELLOW, GREEN
}
// Enum with different access levels
enum CoffeeSize {
SMALL, MEDIUM, LARGE, EXTRA_LARGE
}
public class BasicEnumDemo {
public static void main(String[] args) {
System.out.println("=== BASIC ENUM DECLARATION DEMO ===");
// Using enum values
Day today = Day.MONDAY;
TrafficLight currentLight = TrafficLight.RED;
CoffeeSize myCoffee = CoffeeSize.LARGE;
System.out.println("Today is: " + today);
System.out.println("Traffic light is: " + currentLight);
System.out.println("Coffee size: " + myCoffee);
// Enum in switch statements (perfect match!)
System.out.println("\n=== SWITCH STATEMENT WITH ENUM ===");
switch (today) {
case MONDAY:
System.out.println("Start of work week!");
break;
case FRIDAY:
System.out.println("Weekend is coming!");
break;
case SATURDAY: case SUNDAY:
System.out.println("Weekend!");
break;
default:
System.out.println("Regular work day");
}
// Getting all enum values
System.out.println("\n=== ALL ENUM VALUES ===");
Day[] allDays = Day.values();
for (Day day : allDays) {
System.out.println("Day: " + day);
}
// Enum methods (inherited from java.lang.Enum)
System.out.println("\n=== ENUM METHODS ===");
System.out.println("Name: " + today.name());
System.out.println("Ordinal: " + today.ordinal()); // Position (0-based)
System.out.println("ToString: " + today.toString());
// Converting string to enum
String dayString = "FRIDAY";
Day parsedDay = Day.valueOf(dayString);
System.out.println("Parsed from string: " + parsedDay);
// Comparing enums
System.out.println("\n=== ENUM COMPARISON ===");
System.out.println("today == Day.MONDAY: " + (today == Day.MONDAY));
System.out.println("today.equals(Day.MONDAY): " + today.equals(Day.MONDAY));
// Enum in collections
System.out.println("\n=== ENUMS IN COLLECTIONS ===");
java.util.Set<Day> weekend = java.util.EnumSet.of(Day.SATURDAY, Day.SUNDAY);
System.out.println("Weekend days: " + weekend);
java.util.Map<Day, String> activities = new java.util.EnumMap<>(Day.class);
activities.put(Day.MONDAY, "Work");
activities.put(Day.SATURDAY, "Relax");
System.out.println("Activities: " + activities);
}
}
Output:
=== BASIC ENUM DECLARATION DEMO ===
Today is: MONDAY
Traffic light is: RED
Coffee size: LARGE
=== SWITCH STATEMENT WITH ENUM ===
Start of work week!
=== ALL ENUM VALUES ===
Day: SUNDAY
Day: MONDAY
Day: TUESDAY
Day: WEDNESDAY
Day: THURSDAY
Day: FRIDAY
Day: SATURDAY
=== ENUM METHODS ===
Name: MONDAY
Ordinal: 1
ToString: MONDAY
Parsed from string: FRIDAY
=== ENUM COMPARISON ===
today == Day.MONDAY: true
today.equals(Day.MONDAY): true
=== ENUMS IN COLLECTIONS ===
Weekend days: [SATURDAY, SUNDAY]
Activities: {MONDAY=Work, SATURDAY=Relax}
Example 2: Enum with Fields, Methods, and Constructors
// ✅ ENUM WITH FIELDS, METHODS, AND CONSTRUCTORS
// Each enum constant can have its own data and behavior
enum Planet {
// Enum constants with constructor arguments
MERCURY(3.303e+23, 2.4397e6),
VENUS(4.869e+24, 6.0518e6),
EARTH(5.976e+24, 6.37814e6),
MARS(6.421e+23, 3.3972e6),
JUPITER(1.9e+27, 7.1492e7),
SATURN(5.688e+26, 6.0268e7),
URANUS(8.686e+25, 2.5559e7),
NEPTUNE(1.024e+26, 2.4746e7);
// Fields (instance variables)
private final double mass; // in kilograms
private final double radius; // in meters
// Constructor (automatically private)
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
// Public getters
public double getMass() {
return mass;
}
public double getRadius() {
return radius;
}
// Universal gravitational constant (m^3 kg^-1 s^-2)
public static final double G = 6.67300E-11;
// Method to calculate surface gravity
public double surfaceGravity() {
return G * mass / (radius * radius);
}
// Method to calculate weight on this planet
public double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity();
}
// Override toString for better representation
@Override
public String toString() {
return name() + " {mass=" + String.format("%.2e", mass) +
" kg, radius=" + String.format("%.2e", radius) + " m}";
}
}
// Enum with different types of fields
enum HttpStatus {
// Constants with status code and message
OK(200, "OK"),
CREATED(201, "Created"),
BAD_REQUEST(400, "Bad Request"),
UNAUTHORIZED(401, "Unauthorized"),
FORBIDDEN(403, "Forbidden"),
NOT_FOUND(404, "Not Found"),
INTERNAL_SERVER_ERROR(500, "Internal Server Error");
private final int code;
private final String message;
HttpStatus(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
// Static method to find enum by code
public static HttpStatus fromCode(int code) {
for (HttpStatus status : values()) {
if (status.code == code) {
return status;
}
}
throw new IllegalArgumentException("No HTTP status with code: " + code);
}
// Check if status is successful (2xx)
public boolean isSuccess() {
return code >= 200 && code < 300;
}
// Check if status is client error (4xx)
public boolean isClientError() {
return code >= 400 && code < 500;
}
// Check if status is server error (5xx)
public boolean isServerError() {
return code >= 500 && code < 600;
}
@Override
public String toString() {
return code + " " + message;
}
}
public class AdvancedEnumDemo {
public static void main(String[] args) {
System.out.println("=== ADVANCED ENUM WITH FIELDS AND METHODS ===");
// Planet enum demonstration
System.out.println("\n=== PLANET ENUM DEMO ===");
double earthWeight = 75; // kg
double mass = earthWeight / Planet.EARTH.surfaceGravity();
System.out.println("Your weight on different planets:");
for (Planet p : Planet.values()) {
System.out.printf(" %-8s: %6.2f kg%n", p, p.surfaceWeight(mass));
}
System.out.println("\n=== PLANET DETAILS ===");
for (Planet p : Planet.values()) {
System.out.println(p);
System.out.printf(" Surface gravity: %.2f m/s²%n", p.surfaceGravity());
}
// HTTP Status enum demonstration
System.out.println("\n=== HTTP STATUS ENUM DEMO ===");
HttpStatus status = HttpStatus.OK;
System.out.println("Current status: " + status);
System.out.println("Code: " + status.getCode());
System.out.println("Message: " + status.getMessage());
System.out.println("Is success: " + status.isSuccess());
System.out.println("\n=== ALL HTTP STATUS CODES ===");
for (HttpStatus httpStatus : HttpStatus.values()) {
System.out.printf("%-25s: %-3d - %s%n",
httpStatus.name(), httpStatus.getCode(), httpStatus.getMessage());
}
System.out.println("\n=== FINDING STATUS BY CODE ===");
HttpStatus foundStatus = HttpStatus.fromCode(404);
System.out.println("Status for code 404: " + foundStatus);
System.out.println("Is client error: " + foundStatus.isClientError());
System.out.println("\n=== STATUS CATEGORIES ===");
System.out.println("Successful statuses:");
for (HttpStatus httpStatus : HttpStatus.values()) {
if (httpStatus.isSuccess()) {
System.out.println(" " + httpStatus);
}
}
System.out.println("Client error statuses:");
for (HttpStatus httpStatus : HttpStatus.values()) {
if (httpStatus.isClientError()) {
System.out.println(" " + httpStatus);
}
}
// Using enums in practical scenarios
System.out.println("\n=== PRACTICAL USAGE ===");
processHttpResponse(200);
processHttpResponse(404);
processHttpResponse(500);
}
public static void processHttpResponse(int statusCode) {
HttpStatus status = HttpStatus.fromCode(statusCode);
System.out.println("\nProcessing HTTP response: " + status);
if (status.isSuccess()) {
System.out.println("✅ Success! Processing response data...");
} else if (status.isClientError()) {
System.out.println("❌ Client error! Check your request...");
} else if (status.isServerError()) {
System.out.println("⚠️ Server error! Try again later...");
}
switch (status) {
case OK:
System.out.println(" Everything worked as expected");
break;
case NOT_FOUND:
System.out.println(" The requested resource was not found");
break;
case INTERNAL_SERVER_ERROR:
System.out.println(" Something went wrong on the server");
break;
default:
System.out.println(" Handling status: " + status.getMessage());
}
}
}
Output:
=== ADVANCED ENUM WITH FIELDS AND METHODS ===
=== PLANET ENUM DEMO ===
Your weight on different planets:
MERCURY : 28.30 kg
VENUS : 67.69 kg
EARTH : 75.00 kg
MARS : 28.33 kg
JUPITER : 189.74 kg
SATURN : 79.63 kg
URANUS : 67.95 kg
NEPTUNE : 85.23 kg
=== PLANET DETAILS ===
MERCURY {mass=3.30e+23 kg, radius=2.44e+06 m}
Surface gravity: 3.70 m/s²
VENUS {mass=4.87e+24 kg, radius=6.05e+06 m}
Surface gravity: 8.87 m/s²
EARTH {mass=5.98e+24 kg, radius=6.38e+06 m}
Surface gravity: 9.80 m/s²
MARS {mass=6.42e+23 kg, radius=3.40e+06 m}
Surface gravity: 3.71 m/s²
JUPITER {mass=1.90e+27 kg, radius=7.15e+07 m}
Surface gravity: 24.79 m/s²
SATURN {mass=5.69e+26 kg, radius=6.03e+07 m}
Surface gravity: 10.44 m/s²
URANUS {mass=8.69e+25 kg, radius=2.56e+07 m}
Surface gravity: 8.87 m/s²
NEPTUNE {mass=1.02e+26 kg, radius=2.47e+07 m}
Surface gravity: 11.15 m/s²
=== HTTP STATUS ENUM DEMO ===
Current status: 200 OK
Code: 200
Message: OK
Is success: true
=== ALL HTTP STATUS CODES ===
OK : 200 - OK
CREATED : 201 - Created
BAD_REQUEST : 400 - Bad Request
UNAUTHORIZED : 401 - Unauthorized
FORBIDDEN : 403 - Forbidden
NOT_FOUND : 404 - Not Found
INTERNAL_SERVER_ERROR : 500 - Internal Server Error
=== FINDING STATUS BY CODE ===
Status for code 404: 404 Not Found
Is client error: true
=== STATUS CATEGORIES ===
Successful statuses:
200 OK
201 Created
Client error statuses:
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
=== PRACTICAL USAGE ===
Processing HTTP response: 200 OK
✅ Success! Processing response data...
Everything worked as expected
Processing HTTP response: 404 Not Found
❌ Client error! Check your request...
The requested resource was not found
Processing HTTP response: 500 Internal Server Error
⚠️ Server error! Try again later...
Something went wrong on the server
Example 3: Enum with Constant-Specific Methods
// ✅ ENUM WITH CONSTANT-SPECIFIC METHOD IMPLEMENTATIONS
// Each enum constant can override methods with its own behavior
enum Operation {
// Constants with lambda expressions for behavior
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;
}
},
DIVIDE("/") {
public double apply(double x, double y) {
if (y == 0) {
throw new ArithmeticException("Division by zero!");
}
return x / y;
}
},
POWER("^") {
public double apply(double x, double y) {
return Math.pow(x, y);
}
},
MODULUS("%") {
public double apply(double x, double y) {
return x % y;
}
};
private final String symbol;
Operation(String symbol) {
this.symbol = symbol;
}
// Abstract method - each constant must implement
public abstract double apply(double x, double y);
public String getSymbol() {
return symbol;
}
@Override
public String toString() {
return symbol;
}
}
// Enum with different behaviors for each constant
enum FileType {
TEXT(".txt") {
@Override
public void process(String content) {
System.out.println("Processing text file: " + content);
}
@Override
public boolean isValid(String filename) {
return filename.toLowerCase().endsWith(".txt");
}
},
JSON(".json") {
@Override
public void process(String content) {
System.out.println("Parsing JSON: " + content);
// Simulate JSON parsing
if (content.trim().startsWith("{")) {
System.out.println(" ✓ Valid JSON structure");
} else {
System.out.println(" ✗ Invalid JSON structure");
}
}
@Override
public boolean isValid(String filename) {
return filename.toLowerCase().endsWith(".json");
}
},
XML(".xml") {
@Override
public void process(String content) {
System.out.println("Parsing XML: " + content);
// Simulate XML parsing
if (content.trim().startsWith("<")) {
System.out.println(" ✓ Valid XML structure");
} else {
System.out.println(" ✗ Invalid XML structure");
}
}
@Override
public boolean isValid(String filename) {
return filename.toLowerCase().endsWith(".xml");
}
},
CSV(".csv") {
@Override
public void process(String content) {
System.out.println("Processing CSV: " + content);
String[] rows = content.split("\n");
System.out.println(" Found " + rows.length + " rows");
for (int i = 0; i < Math.min(rows.length, 3); i++) {
System.out.println(" Row " + (i + 1) + ": " + rows[i]);
}
}
@Override
public boolean isValid(String filename) {
return filename.toLowerCase().endsWith(".csv");
}
};
private final String extension;
FileType(String extension) {
this.extension = extension;
}
// Abstract methods that each constant must implement
public abstract void process(String content);
public abstract boolean isValid(String filename);
public String getExtension() {
return extension;
}
// Static method to detect file type from filename
public static FileType fromFilename(String filename) {
for (FileType type : values()) {
if (type.isValid(filename)) {
return type;
}
}
throw new IllegalArgumentException("Unknown file type: " + filename);
}
}
// Enum with strategy pattern
enum NotificationChannel {
EMAIL {
@Override
public void sendNotification(String message, String recipient) {
System.out.println("📧 Sending email to: " + recipient);
System.out.println(" Subject: Notification");
System.out.println(" Body: " + message);
System.out.println(" → Email sent successfully!");
}
@Override
public boolean validateRecipient(String recipient) {
return recipient.contains("@") && recipient.contains(".");
}
},
SMS {
@Override
public void sendNotification(String message, String recipient) {
System.out.println("📱 Sending SMS to: " + recipient);
System.out.println(" Message: " + (message.length() > 20 ?
message.substring(0, 20) + "..." : message));
System.out.println(" → SMS sent successfully!");
}
@Override
public boolean validateRecipient(String recipient) {
// Simple phone number validation
return recipient.matches("\\+?[0-9]{10,15}");
}
},
PUSH {
@Override
public void sendNotification(String message, String recipient) {
System.out.println("📲 Sending push notification to device: " + recipient);
System.out.println(" Title: App Notification");
System.out.println(" Body: " + message);
System.out.println(" → Push notification sent!");
}
@Override
public boolean validateRecipient(String recipient) {
// Device token validation (simplified)
return recipient.length() == 64 && recipient.matches("[0-9a-fA-F]+");
}
};
// Abstract methods
public abstract void sendNotification(String message, String recipient);
public abstract boolean validateRecipient(String recipient);
// Template method with common behavior
public final void sendSecureNotification(String message, String recipient) {
System.out.println("\n=== Sending Secure Notification ===");
if (!validateRecipient(recipient)) {
System.out.println("❌ Invalid recipient: " + recipient);
return;
}
try {
sendNotification(message, recipient);
logNotification("SUCCESS", recipient);
} catch (Exception e) {
System.out.println("❌ Failed to send notification: " + e.getMessage());
logNotification("FAILED", recipient);
}
}
private void logNotification(String status, String recipient) {
System.out.println(" 📊 Log: " + name() + " notification " + status +
" to " + recipient + " at " + java.time.LocalTime.now());
}
}
public class ConstantSpecificMethodsDemo {
public static void main(String[] args) {
System.out.println("=== ENUM WITH CONSTANT-SPECIFIC METHODS ===");
// Operation enum demonstration
System.out.println("\n=== OPERATION ENUM DEMO ===");
double x = 10, y = 3;
for (Operation op : Operation.values()) {
try {
double result = op.apply(x, y);
System.out.printf("%.1f %s %.1f = %.2f%n", x, op, y, result);
} catch (ArithmeticException e) {
System.out.printf("%.1f %s %.1f = ERROR: %s%n", x, op, y, e.getMessage());
}
}
// Calculator simulation
System.out.println("\n=== CALCULATOR SIMULATION ===");
String[] expressions = {"5 + 3", "10 - 4", "6 * 7", "15 / 3", "8 / 0", "2 ^ 8"};
for (String expression : expressions) {
String[] parts = expression.split(" ");
double a = Double.parseDouble(parts[0]);
double b = Double.parseDouble(parts[2]);
Operation op = Operation.valueOf(parts[1].toUpperCase());
try {
double result = op.apply(a, b);
System.out.printf("%s = %.2f%n", expression, result);
} catch (ArithmeticException e) {
System.out.printf("%s = ERROR: %s%n", expression, e.getMessage());
}
}
// FileType enum demonstration
System.out.println("\n=== FILE TYPE PROCESSING ===");
String[] filenames = {"document.txt", "data.json", "config.xml", "records.csv", "image.png"};
for (String filename : filenames) {
System.out.println("\nProcessing: " + filename);
try {
FileType fileType = FileType.fromFilename(filename);
String sampleContent = getSampleContent(fileType);
fileType.process(sampleContent);
} catch (IllegalArgumentException e) {
System.out.println(" ❌ " + e.getMessage());
}
}
// NotificationChannel enum demonstration
System.out.println("\n=== NOTIFICATION SYSTEM ===");
String message = "Hello! This is an important notification from our system.";
NotificationChannel.EMAIL.sendSecureNotification(message, "[email protected]");
NotificationChannel.SMS.sendSecureNotification(message, "+1234567890");
NotificationChannel.PUSH.sendSecureNotification(message, "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6");
System.out.println("\n=== INVALID NOTIFICATIONS ===");
NotificationChannel.EMAIL.sendSecureNotification(message, "invalid-email");
NotificationChannel.SMS.sendSecureNotification(message, "123");
NotificationChannel.PUSH.sendSecureNotification(message, "short-token");
}
private static String getSampleContent(FileType fileType) {
switch (fileType) {
case TEXT:
return "This is a sample text file content.";
case JSON:
return "{\"name\": \"John\", \"age\": 30, \"city\": \"New York\"}";
case XML:
return "<user><name>John</name><age>30</age><city>New York</city></user>";
case CSV:
return "Name,Age,City\nJohn,30,New York\nJane,25,Los Angeles\nBob,35,Chicago";
default:
return "Unknown content";
}
}
}
Output:
=== ENUM WITH CONSTANT-SPECIFIC METHODS ===
=== OPERATION ENUM DEMO ===
10.0 + 3.0 = 13.00
10.0 - 3.0 = 7.00
10.0 * 3.0 = 30.00
10.0 / 3.0 = 3.33
10.0 ^ 3.0 = 1000.00
10.0 % 3.0 = 1.00
=== CALCULATOR SIMULATION ===
5 + 3 = 8.00
10 - 4 = 6.00
6 * 7 = 42.00
15 / 3 = 5.00
8 / 0 = ERROR: Division by zero!
2 ^ 8 = 256.00
=== FILE TYPE PROCESSING ===
Processing: document.txt
Processing text file: This is a sample text file content.
Processing: data.json
Parsing JSON: {"name": "John", "age": 30, "city": "New York"}
✓ Valid JSON structure
Processing: config.xml
Parsing XML: <user><name>John</name><age>30</age><city>New York</city></user>
✓ Valid XML structure
Processing: records.csv
Processing CSV: Name,Age,City
John,30,New York
Jane,25,Los Angeles
Bob,35,Chicago
Found 4 rows
Row 1: Name,Age,City
Row 2: John,30,New York
Row 3: Jane,25,Los Angeles
Processing: image.png
❌ Unknown file type: image.png
=== NOTIFICATION SYSTEM ===
=== Sending Secure Notification ===
📧 Sending email to: [email protected]
Subject: Notification
Body: Hello! This is an important notification from our system.
→ Email sent successfully!
📊 Log: EMAIL notification SUCCESS to [email protected] at 10:30:45.123
=== Sending Secure Notification ===
📱 Sending SMS to: +1234567890
Message: Hello! This is an imp...
→ SMS sent successfully!
📊 Log: SMS notification SUCCESS to +1234567890 at 10:30:45.124
=== Sending Secure Notification ===
📲 Sending push notification to device: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6
Title: App Notification
Body: Hello! This is an important notification from our system.
→ Push notification sent!
📊 Log: PUSH notification SUCCESS to a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6 at 10:30:45.124
=== INVALID NOTIFICATIONS ===
=== Sending Secure Notification ===
❌ Invalid recipient: invalid-email
=== Sending Secure Notification ===
❌ Invalid recipient: 123
=== Sending Secure Notification ===
❌ Invalid recipient: short-token
Example 4: Real-World Enum Usage Patterns
import java.time.DayOfWeek;
import java.time.LocalDate;
// ✅ REAL-WORLD ENUM USAGE PATTERNS
// Configuration enum
enum Environment {
DEVELOPMENT("dev", "http://localhost:8080", true),
TESTING("test", "http://test.example.com", true),
STAGING("staging", "http://staging.example.com", false),
PRODUCTION("prod", "https://example.com", false);
private final String code;
private final String baseUrl;
private final boolean debugEnabled;
Environment(String code, String baseUrl, boolean debugEnabled) {
this.code = code;
this.baseUrl = baseUrl;
this.debugEnabled = debugEnabled;
}
public String getCode() { return code; }
public String getBaseUrl() { return baseUrl; }
public boolean isDebugEnabled() { return debugEnabled; }
public static Environment fromCode(String code) {
for (Environment env : values()) {
if (env.code.equalsIgnoreCase(code)) {
return env;
}
}
throw new IllegalArgumentException("Unknown environment: " + code);
}
public String getDatabaseUrl() {
return baseUrl.replace("http", "jdbc:postgresql") + "/" + code + "_db";
}
}
// State machine enum
enum OrderStatus {
PENDING {
@Override
public OrderStatus next() { return CONFIRMED; }
@Override
public boolean canCancel() { return true; }
},
CONFIRMED {
@Override
public OrderStatus next() { return PROCESSING; }
@Override
public boolean canCancel() { return true; }
},
PROCESSING {
@Override
public OrderStatus next() { return SHIPPED; }
@Override
public boolean canCancel() { return false; }
},
SHIPPED {
@Override
public OrderStatus next() { return DELIVERED; }
@Override
public boolean canCancel() { return false; }
},
DELIVERED {
@Override
public OrderStatus next() { return this; } // Final state
@Override
public boolean canCancel() { return false; }
},
CANCELLED {
@Override
public OrderStatus next() { return this; } // Final state
@Override
public boolean canCancel() { return false; }
};
public abstract OrderStatus next();
public abstract boolean canCancel();
public boolean isFinalState() {
return this == DELIVERED || this == CANCELLED;
}
}
// Permission enum with bit flags
enum Permission {
READ(1), // 0001
WRITE(2), // 0010
EXECUTE(4), // 0100
DELETE(8); // 1000
private final int value;
Permission(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static int combine(Permission... permissions) {
int result = 0;
for (Permission permission : permissions) {
result |= permission.value;
}
return result;
}
public static boolean hasPermission(int permissions, Permission permission) {
return (permissions & permission.value) != 0;
}
public static String describePermissions(int permissions) {
StringBuilder sb = new StringBuilder();
for (Permission perm : values()) {
if (hasPermission(permissions, perm)) {
if (sb.length() > 0) sb.append(", ");
sb.append(perm.name());
}
}
return sb.toString();
}
}
// Singleton pattern with enum (Joshua Bloch's preferred method)
enum DatabaseConnection {
INSTANCE;
private boolean connected = false;
public void connect() {
if (!connected) {
System.out.println("🔗 Connecting to database...");
// Simulate connection logic
try { Thread.sleep(1000); } catch (InterruptedException e) {}
connected = true;
System.out.println("✅ Database connected successfully!");
} else {
System.out.println("ℹ️ Database already connected");
}
}
public void disconnect() {
if (connected) {
System.out.println("🔌 Disconnecting from database...");
connected = false;
System.out.println("✅ Database disconnected");
} else {
System.out.println("ℹ️ Database already disconnected");
}
}
public void executeQuery(String query) {
if (!connected) {
throw new IllegalStateException("Database not connected");
}
System.out.println("📊 Executing query: " + query);
// Simulate query execution
}
}
public class RealWorldEnumPatterns {
public static void main(String[] args) {
System.out.println("=== REAL-WORLD ENUM USAGE PATTERNS ===");
// Environment configuration
System.out.println("\n=== ENVIRONMENT CONFIGURATION ===");
Environment currentEnv = Environment.DEVELOPMENT;
System.out.println("Current Environment: " + currentEnv);
System.out.println("Base URL: " + currentEnv.getBaseUrl());
System.out.println("Database URL: " + currentEnv.getDatabaseUrl());
System.out.println("Debug enabled: " + currentEnv.isDebugEnabled());
System.out.println("\nAll environments:");
for (Environment env : Environment.values()) {
System.out.printf(" %-10s: %-25s | Debug: %-5s | DB: %s%n",
env.name(), env.getBaseUrl(), env.isDebugEnabled(), env.getDatabaseUrl());
}
// Lookup by code
System.out.println("\nLooking up by code:");
System.out.println("'prod' -> " + Environment.fromCode("prod"));
// Order status state machine
System.out.println("\n=== ORDER STATUS STATE MACHINE ===");
OrderStatus status = OrderStatus.PENDING;
System.out.println("Initial status: " + status);
while (!status.isFinalState()) {
System.out.println("Current: " + status +
" | Can cancel: " + status.canCancel() +
" | Next: " + status.next());
status = status.next();
}
System.out.println("Final status: " + status);
// Simulate order processing
System.out.println("\n=== ORDER PROCESSING SIMULATION ===");
simulateOrderProcessing();
// Permission system with bit flags
System.out.println("\n=== PERMISSION SYSTEM ===");
int userPermissions = Permission.combine(Permission.READ, Permission.WRITE);
int adminPermissions = Permission.combine(Permission.READ, Permission.WRITE,
Permission.EXECUTE, Permission.DELETE);
System.out.println("User permissions: " + userPermissions +
" (" + Integer.toBinaryString(userPermissions) + ")");
System.out.println("User can READ: " + Permission.hasPermission(userPermissions, Permission.READ));
System.out.println("User can EXECUTE: " + Permission.hasPermission(userPermissions, Permission.EXECUTE));
System.out.println("User permissions: " + Permission.describePermissions(userPermissions));
System.out.println("Admin permissions: " + adminPermissions +
" (" + Integer.toBinaryString(adminPermissions) + ")");
System.out.println("Admin permissions: " + Permission.describePermissions(adminPermissions));
// Singleton pattern with enum
System.out.println("\n=== DATABASE CONNECTION SINGLETON ===");
DatabaseConnection db1 = DatabaseConnection.INSTANCE;
DatabaseConnection db2 = DatabaseConnection.INSTANCE;
System.out.println("db1 == db2: " + (db1 == db2)); // Same instance
db1.connect();
db2.connect(); // Should show already connected
db1.executeQuery("SELECT * FROM users");
db1.disconnect();
// Enum in business logic
System.out.println("\n=== BUSINESS LOGIC WITH ENUMS ===");
processWeekdayBusiness(DayOfWeek.MONDAY);
processWeekdayBusiness(DayOfWeek.SATURDAY);
}
private static void simulateOrderProcessing() {
OrderStatus status = OrderStatus.PENDING;
System.out.println("Order created with status: " + status);
// Process order through states
String[] actions = {"confirm", "process", "ship", "deliver"};
for (String action : actions) {
if (status.isFinalState()) break;
System.out.println("\nAction: " + action.toUpperCase());
if (action.equals("cancel") && status.canCancel()) {
status = OrderStatus.CANCELLED;
System.out.println("Order cancelled!");
} else {
status = status.next();
System.out.println("Order status: " + status);
}
System.out.println("Can cancel: " + status.canCancel());
System.out.println("Is final: " + status.isFinalState());
}
}
private static void processWeekdayBusiness(DayOfWeek day) {
System.out.println("\nProcessing business for: " + day);
switch (day) {
case MONDAY:
System.out.println(" 📊 Weekly planning meeting");
System.out.println(" 📈 Review metrics from last week");
break;
case FRIDAY:
System.out.println(" 🎉 Team lunch");
System.out.println(" 📋 Week in review meeting");
break;
case SATURDAY: case SUNDAY:
System.out.println(" 🏖️ Weekend - no business activities");
break;
default:
System.out.println(" 💼 Regular work day");
System.out.println(" 📝 Daily standup meeting");
}
// Check if it's a workday
if (day.getValue() >= DayOfWeek.MONDAY.getValue() &&
day.getValue() <= DayOfWeek.FRIDAY.getValue()) {
System.out.println(" ✅ Business hours: 9 AM - 5 PM");
} else {
System.out.println(" ❌ Closed - weekend");
}
}
}
Output:
=== REAL-WORLD ENUM USAGE PATTERNS === === ENVIRONMENT CONFIGURATION === Current Environment: DEVELOPMENT Base URL: http://localhost:8080 Database URL: jdbc:postgresql://localhost:8080/dev_db Debug enabled: true All environments: DEVELOPMENT: http://localhost:8080 | Debug: true | DB: jdbc:postgresql://localhost:8080/dev_db TESTING : http://test.example.com | Debug: true | DB: jdbc:postgresql://test.example.com/test_db STAGING : http://staging.example.com | Debug: false | DB: jdbc:postgresql://staging.example.com/staging_db PRODUCTION : https://example.com | Debug: false | DB: jdbc:postgresql://example.com/prod_db Looking up by code: 'prod' -> PRODUCTION === ORDER STATUS STATE MACHINE === Initial status: PENDING Current: PENDING | Can cancel: true | Next: CONFIRMED Current: CONFIRMED | Can cancel: true | Next: PROCESSING Current: PROCESSING | Can cancel: false | Next: SHIPPED Current: SHIPPED | Can cancel: false | Next: DELIVERED Final status: DELIVERED === ORDER PROCESSING SIMULATION === Order created with status: PENDING Action: CONFIRM Order status: CONFIRMED Can cancel: true Is final: false Action: PROCESS Order status: PROCESSING Can cancel: false Is final: false Action: SHIP Order status: SHIPPED Can cancel: false Is final: false Action: DELIVER Order status: DELIVERED Can cancel: false Is final: true === PERMISSION SYSTEM === User permissions: 3 (11) User can READ: true User can EXECUTE: false User permissions: READ, WRITE Admin permissions: 15 (1111) Admin permissions: READ, WRITE, EXECUTE, DELETE === DATABASE CONNECTION SINGLETON === db1 == db2: true 🔗 Connecting to database... ✅ Database connected successfully! ℹ️ Database already connected 📊 Executing query: SELECT * FROM users 🔌 Disconnecting from database... ✅ Database disconnected === BUSINESS LOGIC WITH ENUMS === Processing business for: MONDAY 📊 Weekly planning meeting 📈 Review metrics from last week ✅ Business hours: 9 AM - 5 PM Processing business for: SATURDAY 🏖️ Weekend - no business activities ❌ Closed - weekend
Enum Declaration Syntax
Basic Syntax:
enum EnumName {
CONSTANT1, CONSTANT2, CONSTANT3;
}
With Fields and Methods:
enum EnumName {
CONSTANT1(value1), CONSTANT2(value2);
private FieldType field;
EnumName(FieldType field) {
this.field = field;
}
public FieldType getField() {
return field;
}
}
With Constant-Specific Methods:
enum EnumName {
CONSTANT1 {
public ReturnType method() { /* implementation */ }
},
CONSTANT2 {
public ReturnType method() { /* implementation */ }
};
public abstract ReturnType method();
}
Best Practices
✅ When to Use Enums:
- Fixed set of constants - Days, status codes, colors
- Type-safe alternatives - Instead of string/integer constants
- Singleton pattern - Single instance enforcement
- Strategy pattern - Different behaviors for each constant
- State machines - Defined state transitions
✅ Enum Design Principles:
- Use descriptive names -
HTTPStatus.OKnotHTTPStatus.STATUS200 - Include useful methods - Validation, conversion, behavior
- Consider immutability - Make fields final
- Override toString() - For meaningful string representation
- Provide valueOf() alternatives - For custom parsing
✅ Performance Benefits:
- == comparison - Faster than equals()
- Switch statements - Optimized by compiler
- Memory efficient - Single instances, no duplication
- Thread-safe - Naturally immutable
Common Pitfalls
// ❌ BAD: Using strings instead of enums
String status = "pending"; // What if someone types "pendng"?
// ✅ GOOD: Using enums
enum OrderStatus { PENDING, CONFIRMED, SHIPPED }
OrderStatus status = OrderStatus.PENDING;
// ❌ BAD: Not handling unknown values
enum Color { RED, GREEN, BLUE }
// How to handle "YELLOW"?
// ✅ GOOD: Provide fromString with default
public static Color fromString(String color) {
try {
return Color.valueOf(color.toUpperCase());
} catch (IllegalArgumentException e) {
return UNKNOWN; // Or throw custom exception
}
}
Conclusion
Enum types are Java's super-powered constants:
- ✅ Type-safe - Compiler prevents invalid values
- ✅ Rich functionality - Fields, methods, constructors
- ✅ Object-oriented - Full class capabilities
- ✅ Performance optimized - Fast comparisons and switches
- ✅ Thread-safe - Immutable by nature
Key Takeaways:
- Use enums instead of string/integer constants for type safety
- Leverage enum capabilities - fields, methods, constant-specific behaviors
- Consider enums for design patterns - Singleton, Strategy, State
- Override toString() for meaningful representations
- Use EnumSet and EnumMap for enum-specific collections
Enums transform what would be error-prone string/integer constants into robust, self-documenting, and powerful constructs that make your code safer, cleaner, and more maintainable!