Hello! In our previous lesson, we established the crucial design principle of "programming to an interface." You refactored our notification system to be loosely coupled, where a NotificationManager could work with any NotificationService implementation. This gave our system flexibility in its behavior.
In this lesson, we'll introduce another powerful feature for writing robust and clean code: enumerations, or enums. While interfaces define a contract for what a class can do, enums define a fixed set of possible values a type can have. We'll explore how to create enums and, more importantly, how to empower them with their own fields, constructors, and methods, turning them from simple lists of names into powerful, self-contained objects. This is a fundamental tool for managing states, categories, and roles in the enterprise applications you aim to build.
Why Do We Need Enums?
Imagine you're building a system to track the status of a support ticket. You might be tempted to use String constants:
public static final String STATUS_OPEN = "OPEN";
public static final String STATUS_IN_PROGRESS = "IN_PROGRESS";
public static final String STATUS_CLOSED = "CLOSED";
This approach is fragile. What happens if someone makes a typo, like "in_progress"? The compiler won't catch it, and you'll have a runtime bug. What if they pass a completely invalid status like "PENDING"? Your code has to handle that possibility everywhere.
Enums solve this problem by creating a new type that can only hold one of the predefined values. This provides compile-time type safety, making your code more readable and far less error-prone.
For a quick and clear introduction to the concept, the following video explains what enums are and when to use them.
Java Enums Explained in 6 Minutes
The "Coding with John" channel provides a concise, 6-minute explanation of Java enums. This will give you a solid foundation on what they are and why they are useful.
Watch the first segment from the beginning to understand the basic concept and syntax for creating a simple enum. Continue watching from this section to see how to use enum values in your code and how to iterate over all possible values using the built-in values() method.
As the video demonstrated, using an enum like DaysOfTheWeek.THURSDAY is much safer and more descriptive than using a raw integer 4 or a string "Thursday".
Beyond Simple Constants: Enums as Classes
Here’s where enums become truly powerful. An enum in Java is not just a list of names; it's a special kind of class. This means it can have fields, constructors, and methods, just like any other class. This allows you to associate data and behavior directly with each constant.
Let's expand on our ticket status idea. Each status could have an associated color for the UI or a numeric code for database storage. An enum can encapsulate this information perfectly.
The Baeldung article, "A Guide to Java Enums," provides an excellent deep dive into this. We'll focus on the section that transforms a basic enum into a more complex one.
A Guide to Java Enums | Baeldung
This article is a comprehensive guide to enums. We will focus on the section that demonstrates how to add rich functionality to them.
Please read Section 5, Fields and Constructors. Pay close attention to how the PizzaStatus enum evolves from a simple list to a complex type with a timeToDelivery field, a constructor, and methods like isReady(). Notice the special syntax for defining the constants with their associated data: ORDERED(5).
As you read, you'll notice a few key rules about enum constructors:
- They are implicitly private. You cannot use
publicorprotected. This is because enums are designed to have a finite, fixed set of instances that you declare within the enum itself. You can't create new instances from outside code usingnew. - The constructor is called automatically once for each enum constant when the class is loaded.
This image clearly shows the compiler error you would get if you tried to declare a public constructor for an enum.

The following video from Telusko reinforces these concepts by building up a Laptop enum with a price field.
This video from Telusko provides another excellent walkthrough of adding state and behavior to enums, with a clear explanation of how constructors work.
First, watch how a price field and a parameterized constructor are added to the Laptop enum from this segment. Next, see how a getter method (getPrice()) is created to access this private field from this part. Finally, watch the explanation of enum constructors from this section. It clarifies why they are private and how they are invoked for each constant.
To see all these pieces together in a clean example, look at the code in the image below. It defines a TicketCategory enum where each constant has a description string. This is a very common and practical use case.

Built-in Enum Methods
The image above also shows the use of ordinal(). Because all enums implicitly extend the java.lang.Enum class, they inherit several useful methods:
values(): Returns an array containing all the enum constants in the order they are declared. You saw this in the "Coding with John" video.name(): Returns the name of the enum constant as aString(e.g.,"HIGH").ordinal(): Returns the zero-based index of the constant in its declaration order (e.g.,CRITICALis 0,HIGHis 1).
A word of caution on ordinal(): While it seems convenient, relying on it can be brittle. If a developer reorders the constants in the enum definition, the ordinal values will change, which could break your application's logic in subtle ways. It's often more robust to define an explicit field (like id or code) in your enum, as we discussed earlier.
Connecting this to your goal of backend development, enums are used extensively. For example, in a Spring Boot application using Spring Security, you would almost certainly define user roles with an enum.
// A typical enum for user roles in a backend application
public enum ERole {
USER,
ADMIN,
MODERATOR
}
This snippet is taken from the article "Implementing Role and Permission-Based Authorization in Spring Boot," which shows a real-world use case you'll encounter later. Using ERole.ADMIN is much safer and clearer than passing around the string "ADMIN".
Your Turn: Enhancing the Notification System
Let's apply this to our ongoing project. We'll add a priority level to our notifications using a feature-rich enum.
Task:
-
Create a
NotificationPriorityEnum:- Create a new enum named
NotificationPriority. - Define three constants:
HIGH,NORMAL, andLOW.
- Create a new enum named
-
Add Fields and a Constructor:
- Give the enum two private
finalfields:int levelandString colorCode. HIGHshould have a level of1and a color code like"#FF0000"(Red).NORMALshould have a level of2and a color code like"#000000"(Black).LOWshould have a level of3and a color code like"#808080"(Gray).- Create a private constructor that takes an
intand aStringto initialize these fields. - Update your constant declarations to call this constructor, e.g.,
HIGH(1, "#FF0000").
- Give the enum two private
-
Add Getter Methods:
- Create public getter methods
getLevel()andgetColorCode()to expose the field values.
- Create public getter methods
-
Update the
NotificationServiceInterface:- Change the signature of the
sendmethod in yourNotificationServiceinterface to:void send(String message, String recipient, NotificationPriority priority);
- Change the signature of the
-
Implement the Changes:
- Update
EmailServiceandSMSServiceto implement the modifiedsendmethod. Inside the method, you can print the message along with the priority's level or color. For example:System.out.println("Sending Email with priority level: " + priority.getLevel()); System.out.println("Recipient: " + recipient + ", Message: " + message); - Update your
NotificationManagerclass so itsdoNotifymethod also accepts aNotificationPriorityand passes it to the underlyingnotificationService.
- Update
-
Test in
Main:- In your
mainmethod, test the new functionality. CreateNotificationManagerinstances and calldoNotifywith different priorities:System.out.println("\n--- Testing with Priorities ---"); NotificationManager emailManager = new NotificationManager(new EmailService()); // Send a high-priority email emailManager.doNotify("System alert: service is down!", "admin@example.com", NotificationPriority.HIGH); // Send a low-priority email emailManager.doNotify("Weekly newsletter is here.", "subscriber@example.com", NotificationPriority.LOW);
- In your
This exercise will solidify your understanding of how to create enums that carry both data and behavior, making your code more expressive and robust.
Conclusion
In this lesson, you've learned that enums are far more than just named constants. They are a powerful tool for creating type-safe, self-contained representations of fixed value sets. By equipping them with fields, constructors, and methods, you can directly associate data and logic with each constant, leading to cleaner and more maintainable code.
Key Takeaways:
- Enums provide type safety for a fixed set of constants, preventing bugs from invalid or misspelled values.
- An enum is a special type of class that can have fields, methods, and private constructors.
- Each enum constant is an instance of the enum class, initialized via its constructor.
- Enums are widely used in backend development to represent states, categories, roles, and more.
In our next lesson, we will take a closer look at the final keyword. You've already used it today to make your enum fields immutable, and next, we'll explore its application to classes, methods, and variables to control inheritance and prevent modification.