Java Enum Examples

1. Introduction

Java has provided native enum types from version 1.5 onwards. Some issues arise with the use of enums in java code which this article attempts to address.

2. Enum Abstract Method

An enum type can have abstract methods just like a class. Each enum constant needs to implement the abstract method. An example follows:

public enum Animal {
  Dog { String sound() { return "bark"; } },
  Cat { String sound() { return "meow"; } },
  Lion { String sound() { return "roar"; } },
  Snake { String sound() { return "hiss"; } };

  abstract String sound();
};

Use it as follows:

String str = "Dog";
Animal animal = Animal.valueOf(Animal.class, str);
System.out.println(animal + " makes sound: " + animal.sound());

// prints
Dog makes sound: bark

3. String to Enum

Use valueOf() to lookup an enum by the name.

private enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY 
};
Day day = Day.valueOf(Day.class, "MONDAY");

The method throws an IllegalArgumentException if the name (with the exact case) is not found.

Day day = Day.valueOf(Day.class, "Monday");

// throws an IllegalArgumentException

4. String to Enum Ignore Case

To lookup an enum by string ignoring the case, you can add a static method to the enum class and use it as shown.

static public Day forNameIgnoreCase(String value) {
    for (Day day : Day.values()) {
	if ( day.name().equalsIgnoreCase(value) ) return day;
    }
    return null;
}

No exceptions are thrown by this code.

String args[] = { "joe", "monday", "Monday", "MONDAY" };
for (String arg : args) {
    Day day = Day.forNameIgnoreCase(arg);
    System.out.println(arg + " => " + day);
}

// prints:
joe => null
monday => MONDAY
Monday => MONDAY
MONDAY => MONDAY

5. EnumSet – Set of Enums

Java also provides a new type EnumSet which is a Set of Enums and provides a bunch of useful operations.

Select a range of enums using EnumSet.range(). Enum constants are returned in the order of declaration.

for (Animal animal : EnumSet.range(Animal.Cat, Animal.Snake)) {
    System.out.println(animal);
}

The EnumSet can also be used as a type-safe alternative to traditional bit flags.

EnumSet.of(Style.BOLD, Style.ITALIC)

You can also add to the set using the normal Set.add() operation. Note that the order of looping is the declared order (and not the add order).

EnumSet<Animal> set = EnumSet.of(Animal.Cat);
set.add(Animal.Dog);
for (Animal animal : set) {
    System.out.println(animal);
}

// prints
Dog
Cat

Remove also works in a similar way. In the following example, we are adding all the enum constants to the set using EnumSet.allOf().

EnumSet<Animal> set = EnumSet.allOf(Animal.class);
set.remove(Animal.Snake);
for (Animal animal : set) {
 System.out.println(animal);
}

// prints
Dog
Cat
Lion

6. EnumMap – Enum as a Key

EnumMap is a specialized implementation of Map provided for cases where an enum is used as the key. According to the javadocs, the storage is compact and efficient. It is used similar to the way regular Maps are used with some change in construction; the enum class must be passed in to the constructor.

EnumMap<Animal,String> sounds = new EnumMap<Animal,String>(Animal.class);
sounds.put(Animal.Dog, "Bark");
sounds.put(Animal.Cat, "Meow");
for (Map.Entry<Animal,String> e : sounds.entrySet()) {
    System.out.println(e.getKey() + " => " + e.getValue());
}

// prints:
Dog => Bark
Cat => Meow

7. Enum Name Map

The implementation of the values() method creates an array every time it is invoked. To avoid invoking this method too many times, you can create a name map and use it for lookup. (Yes, that might possibly count as “premature optimization” but hopefully you are resorting to this approach only when invoking values() multiple times.)

static private enum Period {
    Day, Week, Fortnight, Month, Year;

    private static final Map<String,Period> nameMap = new HashMap<>();
    static {
	for (Period period : Period.values())
	    nameMap.put(period.name(), period);
    };

    static public Period forName(String value)
    {
	return nameMap.get(value);
    }
};

And use it like this. Note again that looking up a non-existent name does not result in an IllegalArgumentException.

String[] args = { "joe", "Day", "Week" };
for (String arg : args) {
    Period period = Period.forName(arg);
    System.out.println(arg + " => " + period);
}

// prints:
joe => null
Day => Day
Week => Week

8. Comparing Enums: == or equals()?

When comparing enum instances, what should you use?

Day day = ...;
if ( day == Day.MONDAY ) {
  // code here
}

if ( day.equals(Day.MONDAY) ) {
  // code here
}

Both are correct. In fact, equals() is implemented using ==. Since == never throws a NullPointerException, one might prefer using that.

9. Should I Use Enum Ordinals?

Enum ordinal is the index of the enum in the list returned by values().

Day[] days = Day.values();
for (int i = 0 ; i < days.length ; i++ ) {
    System.out.println(i + " => " + days[i]);
}

// prints:
0 => SUNDAY
1 => MONDAY
2 => TUESDAY
3 => WEDNESDAY
4 => THURSDAY
5 => FRIDAY
6 => SATURDAY

Sometimes you may want to store or transmit the ordinal as a part of storing the state. Should you use the ordinal in such cases? For instance:

System.out.println("4 => " + days[4]);

// prints
4 => THURSDAY

The answer is no, it is not a good idea to store or use the ordinal. It is a much better idea to store and transmit the name. Since the values() method returns the array in the order of declaration, using the ordinal might return wrong values if the enum definition is modified to add or remove entries.

Store and use the name. If the enum entry is removed later, valueOf() will throw an exception. Which is much better than using wrong values and not knowing about it.

Summary

We have now learnt some basics about enums in java. Enums in java are more powerful than in most other languages. Abstract methods can be declared for the enum and specialized implementation can be defined for each enum constant. Looking up enum constants in a case-insensitive operation is another area arising frequently.

Leave a Reply

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