Use of adding functions/fields to enum cases in Java other than overriding?

Viewed 58

By accident I just discovered that the Java 1.8 compiler allows the following syntax:

enum AnimalType {
    DOG {
        @Override
        public String toString() {
            return "I am a dog";
        }
    },
    CAT {
        @Override
        public String toString() {
            return "I am a cat";
        }

        public void doCatThings() {
            // ...
        }
    },
}

Overriding toString() individually works perfectly fine. A call on an AnimalType.DOG results in the String "I am a dog".

Apart from this though, I couldn't find any information on what this enum case customization could be used for. Note the other public method for the case CAT. When defining any other public method or field, it seems like it can't be accessed from the outside anyway.

So what's the deal about this? Is this just something that is technically correct syntax but pointless?

2 Answers

toString is inherited from Object, but behavior is still polymorphic: DOG and CAT "print themselves" differently. Now your own custom methods (like, sound() in the following example) will make much more sense if you 'll use an abstract method at the level of AnimalType enum definition:

enum AnimalType {
    DOG {
        @Override
        public String toString() {
            return "I am a dog";
        }

        @Override
        public void sound() {
           System.out.println("Meowww");
        }
     
    },
    CAT {
        @Override
        public String toString() {
            return "I am a cat";
        }

        @Override
        public void sound() {
           System.out.println("Woof, I'm a barking dog");
        }
    };

    abstract void sound();
}

Now you can add polymorphic custom behavior to the enum and use it without known the actual animal:


public class SampleClass {

    public static void doSound(AnimalType animal) {
       ...
       animal.sound();
    }
}

// usage:

SampleClass.doSound(AnimalType.DOG);

The actual usages can vary, out of my head, you can implement finite state machine, parsing if enums are tokens, calculations if enums are geometric figures (like calculate volume of 3d figure) and what not. Its a tool for java programmers like many others. Use it wisely :)

As the answer bij @MarkBramnik explained, the primary use is to define methods in the enum type itself, and then have each enum value provide a custom implementation for it.

As you yourself identified, another solid use-case is to use this to provide a custom implementation per enum value for inherited methods. Note that you're not restricted to just stuff from java.lang.Object - enums can implement interfaces!

public interface SoundSource {
    void play();
}

public enum Animal implements SoundSource {
    DOG {
        @Override public void play() {
            AudioSystem.play("woof.mp3");
        }
    }
}

for example.

EDIT: ** Whilst this sounds nice, it doesn't actually work in java - leaving the answer as is, but take it as a 'wouldnt it be nice' feature **

This feature is also useful because it lets enum values serve as a storage dump for methods that go the concept. For example:

enum Animal {
    DOG,
    CAT {
        public void doCatThings() { ... }
    }
}

This is basically a namespacing issue: If you have a method that is related to cats as a concept and not other animals, then you need to put it somewhere. You could make class CatUtils { public static void doCatThings() {} } if you really want, but a Utils class is a bit of a code smell. At the very least it's hard to discover. A nicer place to put such utility methods, if you already have an enum dedicated to the concept already, is on the enum value itself; then you can call Animal.CAT.doCatThings(); instead of CatUtils.doCatThings(); which is slightly nicer.

Related