Java Enums: A Beginner’s Guide

Enums aren’t just your run-of-the-mill constants — they’re way cooler than that. They’re a powerful feature in Java, and if developers know how to wield them, they can write code that’s cleaner, more readable, and, dare I say it, downright elegant. Oh, and bonus points: Enums also help developers handle errors gracefully. Let’s dive in and figure out how.

What Is an Enum, Anyway?

Let’s keep it simple: an enum (short for “enumeration”) is a special data type that allows developers to define a set of named constants. Think of it like a menu at a coffee shop. Developers have a fixed number of options — like SMALLMEDIUM, and LARGE — and developers want to ensure nobody accidentally orders a size like “EXTRA_TINY.” Enums enforce those boundaries, ensuring your code doesn’t wander into weird, unintended territory.

Here’s how developers can define an enum in Java:

public enum CoffeeSize {
    SMALL, MEDIUM, LARGE
}

That’s it! Developers have created an enum with three constants: SMALLMEDIUM, and LARGE. Easy peasy, right?

Why Use Enums?

Developers might be thinking, “Why not just use a bunch of final static constants instead of enums?” Good question. While final static constants can get the job done, enums bring several advantages to the table:

  1. Type Safety: Enums prevent developers from accidentally assigning invalid values. If developers have got an enum for CoffeeSize, developers can’t assign "EXTRA_TINY" or "HUGE" to it. The compiler won’t let you.
  2. Readability: Code with enums is easier to understand at a glance. It’s clear what the valid options are, and the intent behind the code is obvious.
  3. Built-In Methods: Enums come with a bunch of handy methods like values() and valueOf() (more on these in a bit).
  4. Custom Behavior: developers can add enum fields, constructors, and methods. This means they’re not just dumb constants — they can have functionality!

Using Enums in Practice

Let’s take the CoffeeSize example and jazz it up a bit. Say developers want to associate a specific price with each coffee size. Developers can add a field to your enum, along with a constructor and a getter method. Check it out:

public enum CoffeeSize {
    SMALL(2.50),
    MEDIUM(3.50),
    LARGE(4.50);

    private final double price;

    CoffeeSize(double price) {
        this.price = price;
    }

    public double getPrice() {
        return price;
    }
}

Now, developers can do something like this:

public class CoffeeShop {
    public static void main(String[] args) {
        CoffeeSize size = CoffeeSize.MEDIUM;
        System.out.println("You ordered a " + size + " coffee. Price: $" + size.getPrice());
    }
}

When developers run this, they will see:

You ordered a MEDIUM coffee. Price: $3.5

How slick is that?

Handling Java Enums Error Messages with Examples

When working with Java Enums, a common task is handling invalid inputs gracefully and providing clear error messages. Enums allow developers to define a fixed set of constants, but invalid values can still sneak into your program, often from user input or external data sources. Let’s explore how to handle these errors with examples.

Example 1: Handling IllegalArgumentException with Enum.valueOf()

The valueOf() method is used to convert a string to its corresponding enum constant. If the input doesn’t match any defined enum value, it throws an IllegalArgumentException, which we can catch and handle:

public enum CoffeeSize {
    SMALL, MEDIUM, LARGE;
}

public class CoffeeShop {
    public static void main(String[] args) {
        String input = "EXTRA_LARGE"; // Invalid size
        
        try {
            CoffeeSize size = CoffeeSize.valueOf(input.toUpperCase());
            System.out.println("You selected: " + size);
        } catch (IllegalArgumentException e) {
            System.out.println("Error: Invalid coffee size '" + input + "'. Please choose SMALL, MEDIUM, or LARGE.");
        }
    }
}

Output for invalid input:

Error: Invalid coffee size 'EXTRA_LARGE'. Please choose SMALL, MEDIUM, or LARGE.

Example 2: Custom Validation with an Error Message

To avoid relying solely on valueOf(), developers can create a method that validates inputs and provides a clear error message:

public enum CoffeeSize {
    SMALL, MEDIUM, LARGE;

    public static CoffeeSize fromString(String size) {
        for (CoffeeSize coffeeSize : CoffeeSize.values()) {
            if (coffeeSize.name().equalsIgnoreCase(size)) {
                return coffeeSize;
            }
        }
        throw new IllegalArgumentException(
            "Error: '" + size + "' is not a valid coffee size. Valid options are SMALL, MEDIUM, or LARGE."
        );
    }
}

public class CoffeeShop {
    public static void main(String[] args) {
        String input = "tiny"; // Invalid input
        
        try {
            CoffeeSize size = CoffeeSize.fromString(input);
            System.out.println("You selected: " + size);
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
    }
}

Output for invalid input:

Error: 'tiny' is not a valid coffee size. Valid options are SMALL, MEDIUM, or LARGE.

SonarLint Rules with Java Enums

SonarLint is a static code analysis tool that helps developers write cleaner, safer, and more maintainable code by enforcing coding standards and identifying issues. Regarding Java Enums, SonarLint provides specific rules to ensure best practices. Let’s explore one common rule with an example.

Enum constants should be uppercase (java:S115)

// Bad
public enum Color {
    red, green, blue;  // lowercase names
}

// Good
public enum Color {
    RED, GREEN, BLUE;  // uppercase names
}
java:S115

Best practice

  1. Switch statements should handle all enum values
public enum Color {
    RED, GREEN, BLUE;  // uppercase names
}

// Bad
public void processColor(Color color) {
    switch (color) {
        case RED:
            process("red");
            break;
        case GREEN:
            process("green");
            break;
        // Missing BLUE case
    }
}

// Good
public void processColor(Color color) {
    switch (color) {
        case RED:
            process("red");
            break;
        case GREEN:
            process("green");
            break;
        case BLUE:
            process("blue");
            break;
        default:
            throw new IllegalArgumentException("Unknown color: " + color);
    }
}

2. Enum constructors should remain private

// Bad
public enum Status {
    ACTIVE, INACTIVE;
    public Status() {}  // public constructor
}

// Good
public enum Status {
    ACTIVE, INACTIVE;
    Status() {}  // private constructor (default)
}
‘public’ not allowed

Finally

Java enums might look simple at first glance, but they’re packed with features that can make your code more robust and error-resistant. Whether Developers are using them to define a fixed set of constants, add custom behavior, or handle invalid inputs gracefully, enums are a versatile tool every Java developer should master.

This article was originally published on Medium.

Leave a Comment

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