Skip to Content
Course content
Click on the "Edit" button in the top corner of the screen to edit your slide content.

If you're coming from C++ or C#, your first instinct might be that Java's enum is just a glorified way to group a few static final int values together. I see this all the time with developers who treat enums as simple labels. They think of them as a replacement for public static final String STATUS_PENDING = "PENDING";.

Here is why that's a mistake: in Java, an enum is not a constant; it is a class. It's a special kind of class that happens to have a fixed set of instances, but it has all the power of any other Java class. If you treat them as just labels, you're missing out on the best part of the language's type system.

Stop thinking of Enums as labels; start thinking of them as objects

When you define an enum, you aren't just making a list. You are defining a type. Let's look at a common scenario: shipping methods. A beginner might just do this:

public enum ShippingMethod {
    GROUND, AIR, SEA
}

That works, but it's anemic. Usually, a shipping method isn't just a name; it has a cost and a delivery window. Instead of writing a giant switch statement somewhere else in your code to map GROUND to a price, you should put that data directly inside the enum. I always tell my juniors: "Keep the data with the definition."

public enum ShippingMethod {
    GROUND(5.00, 5), 
    AIR(20.00, 1), 
    SEA(2.00, 20);

    private final double baseCost;
    private final int estimatedDays;

    // The constructor is private by default; you can't call it from outside.
    ShippingMethod(double baseCost, int estimatedDays) {
        this.baseCost = baseCost;
        this.estimatedDays = estimatedDays;
    }

    public double calculateCost(double weight) {
        return baseCost + (weight * 0.50);
    }

    public int getEstimatedDays() {
        return estimatedDays;
    }
}

Now, the ShippingMethod isn't just a tag; it's a business object. You've encapsulated the logic for cost calculation inside the enum itself. This means if you add a DRONE method later, you're forced to define its cost and days right there, rather than hunting down every if/else block in your project.

Giving constants their own unique behavior

Now, here is where things get really interesting. Sometimes, a simple field isn't enough because different constants need to behave differently. You might think you need a complex inheritance hierarchy for this, but Java lets you define abstract methods inside an enum.

Imagine we are building a simple calculator for different mathematical operations. We want each operation to "know" how to execute itself. I personally love this pattern because it completely eliminates the need for messy switch statements in your service layer.

public enum Operation {
    ADD {
        @Override
        public double apply(double x, double y) { return x + y; }
    },
    SUBTRACT {
        @Override
        public double apply(double x, double y) { return x - y; }
    },
    MULTIPLY {
        @Override
        public double apply(double x, double y) { return x * y; }
    };

    // Every constant MUST implement this method
    public abstract double apply(double x, double y);
}

Notice how each constant is essentially an anonymous inner class that extends Operation. You can now call Operation.ADD.apply(10, 5) and get 15. The logic is decoupled from the caller and tied directly to the constant.

The "gotchas" of Enum identity

One last thing to keep in mind: because enums are singletons, you should always compare them using == instead of .equals(). While .equals() works, == is null-safe and slightly faster. If you try to compare method == ShippingMethod.GROUND, it will never throw a NullPointerException even if method is null; it'll just return false. It's a small detail, but it's the mark of someone who actually knows how Java handles these under the hood.




📋 Practical Task

Building a Subscription Tier Pricing Engine

You are tasked with creating a subscription management system for a SaaS product. Instead of using a series of if statements to check user tiers, you will implement a robust SubscriptionTier enum.

Requirements:

  • Create an enum named SubscriptionTier with three constants: BASIC, PRO, and ENTERPRISE.
  • Each tier must have a monthlyPrice (double) and a maxUsers (int) assigned via a constructor.
  • Implement an abstract method calculateDiscountedPrice(double percentage).
  • Custom Logic:
    • The BASIC tier should not allow any discounts (it always returns the full price).
    • The PRO and ENTERPRISE tiers should apply the percentage discount to the monthly price.
  • Write a main method to demonstrate that calling SubscriptionTier.BASIC.calculateDiscountedPrice(0.20) returns the original price, while SubscriptionTier.PRO.calculateDiscountedPrice(0.20) returns the price minus 20%.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.