Enums in Java are more powerful than in many other languages. They can have constructors, methods, fields, and even implement interfaces.
Basic Enum Syntax
public enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY } Enum with Constructor, Fields and Methods
Simple Example
public 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 private final double mass; // in kilograms private final double radius; // in meters // Constructor (always private by default) Planet(double mass, double radius) { this.mass = mass; this.radius = radius; } // Methods public double getMass() { return mass; } public double getRadius() { return radius; } public double getSurfaceGravity() { final double G = 6.67300E-11; // gravitational constant return G * mass / (radius * radius); } public double getSurfaceWeight(double otherMass) { return otherMass * getSurfaceGravity(); } } Usage Example
public class PlanetTest { public static void main(String[] args) { double earthWeight = 175; // in pounds double mass = earthWeight / Planet.EARTH.getSurfaceGravity(); for (Planet p : Planet.values()) { System.out.printf("Your weight on %s is %f%n", p, p.getSurfaceWeight(mass)); } } } Advanced Enum Features
Enum with Multiple Fields and Custom Methods
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; } }, DIVIDE("/") { public double apply(double x, double y) { return x / y; } }; private final String symbol; // Constructor Operation(String symbol) { this.symbol = symbol; } // Abstract method - each constant must implement public abstract double apply(double x, double y); // Regular method public String getSymbol() { return symbol; } // Static utility method public static Operation fromSymbol(String symbol) { for (Operation op : values()) { if (op.symbol.equals(symbol)) { return op; } } throw new IllegalArgumentException("Unknown operator: " + symbol); } } Usage
public class Calculator { public static void main(String[] args) { double x = 10, y = 5; for (Operation op : Operation.values()) { System.out.printf("%f %s %f = %f%n", x, op.getSymbol(), y, op.apply(x, y)); } // Using the static method Operation plus = Operation.fromSymbol("+"); System.out.println("5 + 3 = " + plus.apply(5, 3)); } } Enum with State and Behavior
Complex Example with Multiple Constructors
public enum HttpStatus { // Success responses OK(200, "OK"), CREATED(201, "Created"), ACCEPTED(202, "Accepted"), // Client error responses BAD_REQUEST(400, "Bad Request"), UNAUTHORIZED(401, "Unauthorized"), FORBIDDEN(403, "Forbidden"), NOT_FOUND(404, "Not Found"), // Server error responses INTERNAL_SERVER_ERROR(500, "Internal Server Error"), NOT_IMPLEMENTED(501, "Not Implemented"), BAD_GATEWAY(502, "Bad Gateway"); private final int code; private final String description; private final Category category; // Regular constructor HttpStatus(int code, String description) { this.code = code; this.description = description; this.category = determineCategory(code); } // Private helper method private Category determineCategory(int code) { if (code >= 200 && code < 300) return Category.SUCCESS; if (code >= 400 && code < 500) return Category.CLIENT_ERROR; if (code >= 500 && code < 600) return Category.SERVER_ERROR; return Category.UNKNOWN; } // Methods public int getCode() { return code; } public String getDescription() { return description; } public Category getCategory() { return category; } public boolean isSuccess() { return category == Category.SUCCESS; } public boolean isError() { return category == Category.CLIENT_ERROR || category == Category.SERVER_ERROR; } // Static lookup method public static HttpStatus fromCode(int code) { for (HttpStatus status : values()) { if (status.code == code) { return status; } } throw new IllegalArgumentException("Unknown HTTP status code: " + code); } // Nested enum public enum Category { SUCCESS, CLIENT_ERROR, SERVER_ERROR, UNKNOWN } @Override public String toString() { return code + " " + description; } } Usage
public class HttpStatusTest { public static void main(String[] args) { HttpStatus status = HttpStatus.NOT_FOUND; System.out.println("Code: " + status.getCode()); System.out.println("Description: " + status.getDescription()); System.out.println("Category: " + status.getCategory()); System.out.println("Is error: " + status.isError()); System.out.println("Is success: " + status.isSuccess()); System.out.println("ToString: " + status); // Lookup by code HttpStatus found = HttpStatus.fromCode(200); System.out.println("Found: " + found); } } Enum Implementing Interface
// Interface public interface Cacheable { String getCacheKey(); boolean isCacheable(); } // Enum implementing interface public enum UserRole implements Cacheable { ADMIN("admin", 1, true), MODERATOR("moderator", 2, true), USER("user", 3, true), GUEST("guest", 4, false); private final String roleName; private final int level; private final boolean cacheable; UserRole(String roleName, int level, boolean cacheable) { this.roleName = roleName; this.level = level; this.cacheable = cacheable; } // Interface method implementations @Override public String getCacheKey() { return "ROLE_" + name(); } @Override public boolean isCacheable() { return cacheable; } // Additional methods public String getRoleName() { return roleName; } public int getLevel() { return level; } public boolean hasPermission(String permission) { // Logic to check permissions based on role level return this.level <= getRequiredLevel(permission); } private int getRequiredLevel(String permission) { // Permission level mapping logic return switch (permission) { case "DELETE" -> 1; case "EDIT" -> 2; case "VIEW" -> 3; default -> 4; }; } } Enum with Singleton Pattern
public enum DatabaseConnection { INSTANCE; private Connection connection; DatabaseConnection() { // Initialize connection initializeConnection(); } private void initializeConnection() { try { // Simulate connection creation System.out.println("Creating database connection..."); // this.connection = DriverManager.getConnection(url); } catch (Exception e) { throw new RuntimeException("Failed to create database connection", e); } } public Connection getConnection() { return connection; } public void executeQuery(String query) { System.out.println("Executing: " + query); // Actual query execution logic } public void close() { try { if (connection != null && !connection.isClosed()) { connection.close(); } } catch (SQLException e) { System.err.println("Error closing connection: " + e.getMessage()); } } } Singleton Usage
public class SingletonDemo { public static void main(String[] args) { // Get the singleton instance DatabaseConnection db = DatabaseConnection.INSTANCE; db.executeQuery("SELECT * FROM users"); // All calls to INSTANCE return the same instance DatabaseConnection sameInstance = DatabaseConnection.INSTANCE; System.out.println("Same instance? " + (db == sameInstance)); // true } } Best Practices
- Use descriptive names for enum constants
- Keep enum constructors private (they already are by default)
- Make enum fields final when possible for immutability
- Override toString() for better readability
- Use enum for fixed set of constants that won't change frequently
- Consider using enums instead of boolean parameters for better readability
// BAD - boolean parameters are confusing public void setVisible(boolean visible, boolean modal) // GOOD - enum parameters are clear public void setVisible(Visibility visible, Modality modal) public enum Visibility { VISIBLE, HIDDEN } public enum Modality { MODAL, MODELESS } Key Benefits
- Type safety - Compiler prevents invalid values
- Rich functionality - Can have methods, fields, and implement interfaces
- Singleton support - Natural implementation of singleton pattern
- Serialization safety - Built-in serialization support
- Switch statement compatibility - Can be used in switch statements
Enums with constructors and methods provide a powerful way to represent fixed sets of related constants with associated behavior and data.