Java Enum Tutorial: How to Define and Use Enums in Java with Examples

Enums were introduced in Java 5 (JDK 1.5) as a way to define a collection of named constants in a type safe manner. Unlike enums in older languages (like C or C++), Java enums are far more powerful since they are implemented using class concepts and can contain constructors, methods, and variables.

What is an Enum?

  • Enum is a special data type used to define a group of named constants.
  • Each enum constant is implicitly:
    • publicstatic, and final.
  • Enums make the code readable, maintainable, and less error-prone compared to using int or String constants.

Example :

enum Month {
  JAN,FEB,MAR,DEC;
}

Internal Implementation of Enum

  • Internally, an enum is implemented as a class.
  • Every enum constant is a reference variable that points to its own enum object.
  • You can think of enums as a fixed set of static final objects.

Enum Declaration and Usage :

enum Month{
    JAN, FEB, MAR, DEC; // semicolon at the end is optional if no extra members
}

class Test {
    public static void main(String[] args) {
        Month mon = Month.FEB;
        System.out.println(mon);
    }
}

Output:

FEB

👉 Note: Since enum constants are implicitly static, we can access them using EnumName.CONSTANT.

Enum with Switch Statement :

Before Java 5, switch allowed only byte,short,char,int (and their wrappers). From Java 5 onwardsenum types can also be used in a switch.

enum PaymentStatus {
    PENDING, PROCESSING, SUCCESS, FAILED;
}

class Test {
    public static void main(String[] args) {
        PaymentStatus status = PaymentStatus.PROCESSING;

        switch (status) {
            case PENDING:
                System.out.println("Payment is pending. Please wait...");
                break;
            case PROCESSING:
                System.out.println("Payment is being processed. Do not refresh the page.");
                break;
            case SUCCESS:
                System.out.println("Payment successful! Thank you for your purchase.");
                break;
            case FAILED:
                System.out.println("Payment failed. Please try again.");
                break;
            default:
                System.out.println("Unknown payment status.");
        }
    }
}

Example:

Output :

Payment is being processed. Do not refresh the page.

👉 Every case label must be a valid enum constant, otherwise you’ll get a compile-time error.

✅Enum and Inheritance

  • Every enum in Java is implicitly a child of java.lang.Enum.
  • Hence, enums cannot extend other classes.
  • Enums are implicitly final, so they cannot be extended.
  • But enums can implement interfaces.

✅Useful Enum Methods

  1. values() – returns all constants as an array.
  2. ordinal() – returns the index (zero-based position) of the constant.
  3. valueOf(String name) – returns the enum constant with the specified name 

Enum values():

  • The values() method is a built-in static method that is automatically added by the Java compiler for every enum.
    👉 It returns an array of all the constants defined in the enum, in the order they are declared.
  • Return type: EnumType[]

📌 Syntax :

public static EnumType[] values()
✅ Why Use values()?
  • To iterate over all enum constants.
  • Useful when you want to display options, validate input, or implement logic based on all possible values.

Example :

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

public class EnumExample {
    public static void main(String[] args) {
        Day[] days = Day.values();  // Calls the values() method
        
        for (Day day : days) {
            System.out.println(day);
        }
    }
}

Output :

MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY
SUNDAY

ordinal():

The ordinal() method is a built-in method provided by Java for enum constants.
👉 It returns the position (index) of the enum constant in its declaration, starting from 0.

  • Return type: int

📌 Syntax :

int ordinal() 
✅ Why Use ordinal()?
  • To get the relative position of a constant in the enum.
  • It is helpful when you need the position or order of the enum constant (e.g., for iteration, comparison, or sorting purposes).
    ⚠️ However, avoid using ordinal() for persistent logic (e.g., storing in databases) because adding or reordering constants changes ordinal values.

Example :

public enum Priority {
    LOW, MEDIUM, HIGH, CRITICAL;
}
public class OrdinalExample {
    public static void main(String[] args) {
        for (Priority level : Priority.values()) {
            System.out.println(level + " has ordinal: " + level.ordinal());
        }
    }
}

Output :

LOW has ordinal: 0  
MEDIUM has ordinal: 1  
HIGH has ordinal: 2  
CRITICAL has ordinal: 3  

📌 Notes :

⚠️ Don’t use ordinal() for business logic that persists data (e.g., database values), because adding/reordering enum constants changes their ordinal values, which breaks the logic.

valueOf(String name)

The valueOf(String name) method is a static method automatically provided by the Java compiler for every enum.
👉 It returns the enum constant that exactly matches the given string name

  • Returns the enum constant with the specified name.
  • The name must exactly match the declared constant (case-sensitive).
  • Return type: EnumType
  • Use case: Useful for converting a string into the corresponding enum constant.

📌 Syntax :

  public static EnumType valueOf(String name)
Why Use valueOf(String name) in Enum?

The valueOf(String name) method is used to convert a String into its corresponding Enum constant.

✅ Key Use Cases:
  1. User Input Conversion
    When a user provides input as a string (e.g., from a form, API, or command line), you can convert it to the corresponding enum constant for type-safe processing.
  2. Configuration Parsing
    Configuration files often store values as strings. Using valueOf(), you can convert these string values into enums for easy and reliable usage in your code.
  3. Validation
    Instead of using complex if-else chains to validate a string against a predefined set of constants, valueOf() allows direct validation by attempting the conversion (and handling exceptions if invalid).

Example :

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

public class ValueOfExample {
    public static void main(String[] args) {
        String input = "FRIDAY";
        
        // Convert String to Enum constant
        Day day = Day.valueOf(input);
        
        System.out.println("Enum constant from String: " + day);
    }
}


 

Output :

Enum constant from String: FRIDAY

⚠️ Important Note:

  • ✔ The input string must match the enum constant name exactly (case-sensitive).
  • ❌ Otherwise, it throws IllegalArgumentException
  • "monday" (lowercase) would fail because enum names are case-sensitive.
  • null input throws NullPointerException.

✅ So yes, valueOf(String name) is always available for enums in Java, either via the compiler-generated method or the generic Enum.valueOf() method.

📌Note : 

  • ordinal() is defined in the java.lang.Enum class.
  • valueOf(String) is also defined in the Enum class. 
  • values() is not defined in Enum; instead, it is a synthetic method automatically generated by the compiler for each enum type. That’s why you won’t find it in the JDK source of Enum.

✅ Key Differences :

Featureordinal()valueOf(String name)values()
PurposeReturns index (position) of constantReturns enum constant by its nameReturns an array of all enum constants
Return TypeintEnum type itselfEnum array (EnumType[])
InputNo input (called on enum constant)Takes String argumentNo input (called on enum type)
Example UsageDay.MONDAY.ordinal()0Day.valueOf("MONDAY") → Day.MONDAYDay.values() → [MONDAY, TUESDAY, …]
RiskChanges if enum order is modifiedThrows IllegalArgumentException if not foundNone (safe, but array order depends on enum order)

Enum with Constructors and Fields

Enums in Java are more powerful than simple lists of constants.

  • 👉 You can define fields, constructors, and methods inside an enum to associate additional data with each constant.
  • 👉Each enum constant is actually an object, and constructors are executed at class loading time.
✅ Why Use Enum Fields and Constructors?
  • To store additional information (metadata) for each enum constant.
  • Helps model real-world entities more effectively.
  • Makes the code cleaner, avoids external mappings (e.g., maps or switch cases).

📌 Syntax

public enum EnumName {
  CONSTANT1(value1),
  CONSTANT2(value2);

  private DataType field; // Field to store additional data
  // Constructor
  EnumName(DataType field) {
    this.field = field;
  }

  // Getter
  public DataType getField() {
    return field;
  }
}

Example :

Step 1 – Define the Enum(UserRole.java)

public enum UserRole {
    ADMIN(1, "Full access to all system features"),
    MODERATOR(2, "Can manage user content and moderate discussions"),
    USER(3, "Standard user with limited access"),
    GUEST(4, "Read-only access to public content");

    private final int accessLevelCode;
    private final String description;

    // Constructor
    UserRole(int accessLevelCode, String description) {
        this.accessLevelCode = accessLevelCode;
        this.description = description;
    }

    // Getters
    public int getAccessLevelCode() {
        return accessLevelCode;
    }

    public String getDescription() {
        return description;
    }
}

Step 2 – Using the Enum in Application(UserAccessTest.java)

public class UserAccessTest {
    public static void main(String[] args) {
        UserRole userRole = UserRole.MODERATOR;

        System.out.println("User Role: " + userRole);
        System.out.println("Access Level Code: " + userRole.getAccessLevelCode());
        System.out.println("Description: " + userRole.getDescription());

        // Display all Access Levels
        System.out.println("\nAll Access Levels:");
        for (UserRole role : UserRole.values()) {
            System.out.printf("%s (%d): %s%n",
                role, role.getAccessLevelCode(), role.getDescription());
        }
    }
}

Output :

User Role: MODERATOR
Access Level Code: 2
Description: Can manage user content and moderate discussions

All Access Levels:
ADMIN (1): Full access to all system features
MODERATOR (2): Can manage user content and moderate discussions
USER (3): Standard user with limited access
GUEST (4): Read-only access to public content  

📌 Note :

  • 👉 You cannot create enum objects manually (new UserRole() is not allowed). They are created internally at load time.
  • 👉 This way, each UserRole constant represents a real application role with an access level (like permissions in a system).

✅ Why Is This Useful in Real Applications?

  • Instead of hardcoding access levels, this enum stores both a code (levelCode) and a description.
  • Helps manage user permissions in a type-safe and centralized way.
  • Easy to display in UI (dropdowns) or use in logic:
if (userAccess == AccessLevel.ADMIN) {
    System.out.println("Grant full system access");
}

📌Note : Using fields and constructors in enums makes your code cleaner and models real-world scenarios more effectively than plain enums or constants.

Enum with Methods

An enum in Java can have fields, constructors, and methods just like a regular class.

  • 👉 Methods allow adding behavior to enums, making them powerful for modeling real-world concepts.
  • 👉Enums can override methods just like classes.
Why Use Methods in Enum?
  • To provide logic related to the enum constants.
  • Avoids switch-case or if-else statements scattered across the code.
  • Encourages encapsulation and clean code structure.

📌 Syntax :

public enum EnumName {
    CONSTANT1, CONSTANT2;
    
    // Custom method
    public ReturnType methodName() {
        // Logic
    }
}

Enum Example with Methods and Override

public enum NotificationType {
    EMAIL {
        @Override
        public void send() {
            System.out.println("Sending Email Notification...");
        }
    },
    SMS {
        @Override
        public void send() {
            System.out.println("Sending SMS Notification...");
        }
    },
    PUSH {
        // Uses default implementation
    };

    // Default behavior
    public void send() {
        System.out.println("Sending Push Notification...");
    }
}
//Main class
public class Test {
    public static void main(String[] args) {
        for (NotificationType type : NotificationType.values()) {
            type.send();
        }
    }
}

Output :

Sending Email Notification...  
Sending SMS Notification...  
Sending Push Notification...  

✅ Explanation

  • Each enum constant (EMAIL, SMS) overrides the send() method with its own implementation.
  • The PUSH constant uses the default implementation of send().
  • This pattern is useful when different constants require different behaviors.

Static Import with Enum

What Is Static Import in Java?

Normally, to access enum constants, you use the full reference like:

Day.MONDAY
  • 👉 The static import feature allows you to import static members (including enum constants) directly, so you don’t need to prefix them with the enum type every time.
  • 👉 You can use static imports to avoid qualifying enum constants.

✅ Why Use Static Import with Enum?

  • 👉 Improves code readability by avoiding repetitive enum type references.
  • 👉 Makes code cleaner when using enums frequently (like in switch cases or comparisons).

📌 Syntax of Static Import

import static packageName.EnumType.*;

This imports all enum constants statically.

Or, import a specific constant:

import static packageName.EnumType.CONSTANT_NAME;

Example :

package pack1;
public enum Fish {
    STAR, GUPPY;
}
package pack2;
import static pack1.Fish.*;

class A {
    public static void main(String[] args) {
        System.out.println(STAR);
        System.out.println(GUPPY);
    }
}

Valid imports:

  1. import static pack1.Fish.*; 
  2. import static pack1.Fish.STAR; ✅

Invalid imports:

  1. import pack1.*; ❌
  2. import pack1.Fish; ❌

📝Important

  • ⚠️ Avoid overusing static imports for large enums in complex projects, as it can reduce code clarity if multiple enums have overlapping constant names.
  • ✅ Recommended for enums with small, well-defined constants frequently used in the same context.

🎯Key Points (Latest Java Versions ✅)

  • Enums are type-safe constants.
  • They can have fields, methods, and constructors.
  • They cannot extend other classes, but can implement interfaces.
  • Enums are thread-safe since all constants are created at class loading.
  • From Java 5 onwards, enums can be used in switch.
  • Useful methods: values()ordinal()name()compareTo().
  • They work seamlessly with Collections, Generics, and Streams (Java 8+).

📌You can also explore how to identify enum types using the isEnum() method in Java.

Backend developer working with Java, Spring Boot, Microservices, NoSQL, and AWS. I love sharing knowledge, practical tips, and clean code practices to help others build scalable applications.

Leave a Reply

Your email address will not be published. Required fields are marked *