227

I just found out that Java allows enums to implement an interface. What would be a good use case for that?

unj2
  • 52,135
  • 87
  • 247
  • 375

16 Answers16

297

Here's one example (a similar/better one is found in Effective Java 2nd Edition):

public interface Operator {
    int apply (int a, int b);
}

public enum SimpleOperators implements Operator {
    PLUS { 
        int apply(int a, int b) { return a + b; }
    },
    MINUS { 
        int apply(int a, int b) { return a - b; }
    };
}

public enum ComplexOperators implements Operator {
    // can't think of an example right now :-/
}

Now to get a list of both the Simple + Complex Operators:

List<Operator> operators = new ArrayList<Operator>();

operators.addAll(Arrays.asList(SimpleOperators.values()));
operators.addAll(Arrays.asList(ComplexOperators.values()));

So here you use an interface to simulate extensible enums (which wouldn't be possible without using an interface).

helpermethod
  • 59,493
  • 71
  • 188
  • 276
  • 3
    Complex operators could be "pow" and the like. – Pimgd Aug 17 '16 at 21:14
  • 5
    First time ever seeing that Enum syntax (with the curly braces after the members), and I've been programming with Java for 6 years. TIL. – jmrah Aug 29 '19 at 23:44
155

Enums don't just have to represent passive sets (e.g. colours). They can represent more complex objects with functionality, and so you're then likely to want to add further functionality to these - e.g. you may have interfaces such as Printable, Reportable etc. and components that support these.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
26

The Comparable example given by several people here is wrong, since Enum already implements that. You can't even override it.

A better example is having an interface that defines, let's say, a data type. You can have an enum to implement the simple types, and have normal classes to implement complicated types:

interface DataType {
  // methods here
}

enum SimpleDataType implements DataType {
  INTEGER, STRING;

  // implement methods
}

class IdentifierDataType implements DataType {
  // implement interface and maybe add more specific methods
}
Jorn
  • 20,612
  • 18
  • 79
  • 126
  • 2
    Yes.Weird !!. Enum already implements the Comparable interface and doesnt permit to override. I looked up java source code for enum class and couldnt find the compareTo implementation. Can anyone tell me whats gets compared inside a compareTo method an ENUM? – Akh Aug 21 '12 at 01:42
  • 2
    @AKh it compares the ordinals, meaning the natural ordering is the order the enum constants are in the source file. – Jorn Aug 21 '12 at 21:43
  • Enum vars are final and so compare occurs with == , right? – djangofan Feb 27 '19 at 17:46
22

There is a case I often use. I have a IdUtil class with static methods to work with objects implementing a very simple Identifiable interface:

public interface Identifiable<K> {
    K getId();
}


public abstract class IdUtil {

    public static <T extends Enum<T> & Identifiable<S>, S> T get(Class<T> type, S id) {
        for (T t : type.getEnumConstants()) {
            if (Util.equals(t.getId(), id)) {
                return t;
            }
        }
        return null;
    }

    public static <T extends Enum<T> & Identifiable<S>, S extends Comparable<? super S>> List<T> getLower(T en) {
        List<T> list = new ArrayList<>();
        for (T t : en.getDeclaringClass().getEnumConstants()) {
             if (t.getId().compareTo(en.getId()) < 0) {
                 list.add(t);
            }
        }
        return list;
    }
}

If I create an Identifiable enum:

    public enum MyEnum implements Identifiable<Integer> {

        FIRST(1), SECOND(2);

        private int id;

        private MyEnum(int id) {
            this.id = id;
        }

        public Integer getId() {
            return id;
        }

    }

Then I can get it by its id this way:

MyEnum e = IdUtil.get(MyEnum.class, 1);
sinuhepop
  • 20,010
  • 17
  • 72
  • 107
13

Since Enums can implement interfaces they can be used for strict enforcing of the singleton pattern. Trying to make a standard class a singleton allows...

  • for the possibility of using reflection techniques to expose private methods as public
  • for inheriting from your singleton and overriding your singleton's methods with something else

Enums as singletons help to prevent these security issues. This might have been one of the contributing reasons to let Enums act as classes and implement interfaces. Just a guess.

See https://stackoverflow.com/questions/427902/java-enum-singleton and Singleton class in java for more discussion.

Community
  • 1
  • 1
Tansir1
  • 1,789
  • 2
  • 15
  • 28
  • 1
    `for inheriting from your singleton and overriding your singleton's methods with something else`. you can just use a `final class` to prevent that – Dylanthepiguy Apr 19 '17 at 05:07
11

It's required for extensibility -- if someone uses an API you've developed, the enums you define are static; they can't be added to or modified. However, if you let it implement an interface, the person using the API can develop their own enum using the same interface. You can then register this enum with an enum manager which conglomerates the enums together with the standard interface.

Edit: @Helper Method has the perfect example of this. Think about having other libraries defining new operators and then telling a manager class that 'hey, this enum exists -- register it'. Otherwise, you'd only be able to define Operators in your own code - there'd be no extensibility.

Chris Dennett
  • 22,412
  • 8
  • 58
  • 84
9

The post above that mentioned strategies didn't stress enough what a nice lightweight implementation of the strategy pattern using enums gets you:

public enum Strategy {

  A {
    @Override
    void execute() {
      System.out.print("Executing strategy A");
    }
  },
  
  B {
    @Override
    void execute() {
      System.out.print("Executing strategy B");
    }
  };

  abstract void execute();
}

You can have all your strategies in one place without needing a separate compilation unit for each. You get a nice dynamic dispatch with just:

Strategy.valueOf("A").execute();

Makes java read almost like a tasty loosely typed language!

Robert Moskal
  • 21,737
  • 8
  • 62
  • 86
7

Most common usage for this would be to merge the values of two enums into one group and treat them similarly. For example, see how to join Fruits and Vegatables.

Community
  • 1
  • 1
husayt
  • 14,553
  • 8
  • 53
  • 81
7

Enums are just classes in disguise, so for the most part, anything you can do with a class you can do with an enum.

I cannot think of a reason that an enum should not be able to implement an interface, at the same time I cannot think of a good reason for them to either.

I would say once you start adding thing like interfaces, or method to an enum you should really consider making it a class instead. Of course I am sure there are valid cases for doing non-traditional enum things, and since the limit would be an artificial one, I am in favour of letting people do what they want there.

TofuBeer
  • 60,850
  • 18
  • 118
  • 163
  • 4
    "... so for the most part anything you can do with a class you can do with an enum", yet I can't say have my enum inherit from an abstract class. So yeah, emphasis on "for the most part". – Adam Parkin Apr 23 '13 at 22:25
  • 5
    That is because enums all extend java.lang.Enum, and Java classes can only extend from one class. – TofuBeer Apr 23 '13 at 22:51
6

For example if you have a Logger enum. Then you should have the logger methods such as debug, info, warning and error in the interface. It makes your code loosely coupled.

Johan
  • 335
  • 3
  • 6
5

One of the best use case for me to use enum's with interface is Predicate filters. It's very elegant way to remedy lack of typness of apache collections (If other libraries mayn't be used).

import java.util.ArrayList;
import java.util.Collection;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;


public class Test {
    public final static String DEFAULT_COMPONENT = "Default";

    enum FilterTest implements Predicate {
        Active(false) {
            @Override
            boolean eval(Test test) {
                return test.active;
            }
        },
        DefaultComponent(true) {
            @Override
            boolean eval(Test test) {
                return DEFAULT_COMPONENT.equals(test.component);
            }
        }

        ;

        private boolean defaultValue;

        private FilterTest(boolean defautValue) {
            this.defaultValue = defautValue;
        }

        abstract boolean eval(Test test);

        public boolean evaluate(Object o) {
            if (o instanceof Test) {
                return eval((Test)o);
            }
            return defaultValue;
        }

    }

    private boolean active = true;
    private String component = DEFAULT_COMPONENT;

    public static void main(String[] args) {
        Collection<Test> tests = new ArrayList<Test>();
        tests.add(new Test());

        CollectionUtils.filter(tests, FilterTest.Active);
    }
}
Anton Bessonov
  • 9,208
  • 3
  • 35
  • 38
5

When creating constants in a jar file, it is often helpful to let users extend enum values. We used enums for PropertyFile keys and got stuck because nobody could add any new ones! Below would have worked much better.

Given:

public interface Color {
  String fetchName();
}

and:

public class MarkTest {

  public static void main(String[] args) {
    MarkTest.showColor(Colors.BLUE);
    MarkTest.showColor(MyColors.BROWN);
  }

  private static void showColor(Color c) {
    System.out.println(c.fetchName());
  }
}

one could have one enum in the jar:

public enum Colors implements Color {
  BLUE, RED, GREEN;
  @Override
  public String fetchName() {
    return this.name();
  }
}

and a user could extend it to add his own colors:

public enum MyColors implements Color {
  BROWN, GREEN, YELLOW;
  @Override
  public String fetchName() {
    return this.name();
  }
}
markthegrea
  • 3,731
  • 7
  • 55
  • 78
4

Another posibility:

public enum ConditionsToBeSatisfied implements Predicate<Number> {
    IS_NOT_NULL(Objects::nonNull, "Item is null"),
    IS_NOT_AN_INTEGER(item -> item instanceof Integer, "Item is not an integer"),
    IS_POSITIVE(item -> item instanceof Integer && (Integer) item > 0, "Item is negative");

    private final Predicate<Number> predicate;
    private final String notSatisfiedLogMessage;

    ConditionsToBeSatisfied(final Predicate<Number> predicate, final String notSatisfiedLogMessage) {
        this.predicate = predicate;
        this.notSatisfiedLogMessage = notSatisfiedLogMessage;
    }

    @Override
    public boolean test(final Number item) {
        final boolean isNotValid = predicate.negate().test(item);

        if (isNotValid) {
            log.warn("Invalid {}. Cause: {}", item, notSatisfiedLogMessage);
        }

        return predicate.test(item);
    }
}

and using:

Predicate<Number> p = IS_NOT_NULL.and(IS_NOT_AN_INTEGER).and(IS_POSITIVE);
3

Enums are like Java Classes, they can have Constructors, Methods, etc. The only thing that you can't do with them is new EnumName(). The instances are predefined in your enum declaration.

Cosmin Cosmin
  • 1,526
  • 1
  • 16
  • 34
  • What about `enum Foo extends SomeOtherClass`? So not quite the same thing as a regular class, in fact, quite different. – Adam Parkin Apr 23 '13 at 22:26
  • @Adam: I would say that the ways in which Enums resemble classes are much more numerous than the ways in which they differ from classes. But, no, they are not identical. – scottb Apr 29 '13 at 13:35
  • if you decompile an enum you will see it's a class which extends Enumeration and has the "constants" already instantiated in constructor / initialization fields. – Cosmin Cosmin Apr 30 '13 at 10:35
2

Here's my reason why ...

I have populated a JavaFX ComboBox with the values of an Enum. I have an interface, Identifiable (specifying one method: identify), that allows me to specify how any object identifies itself to my application for searching purposes. This interface enables me to scan lists of any type of objects (whichever field the object may use for identity) for an identity match.

I'd like to find a match for an identity value in my ComboBox list. In order to use this capability on my ComboBox containing the Enum values, I must be able to implement the Identifiable interface in my Enum (which, as it happens, is trivial to implement in the case of an Enum).

scottb
  • 9,908
  • 3
  • 40
  • 56
1

I used an inner enum in an interface describing a strategy to keep instance control (each strategy is a Singleton) from there.

public interface VectorizeStrategy {

    /**
     * Keep instance control from here.
     * 
     * Concrete classes constructors should be package private.
     */
    enum ConcreteStrategy implements VectorizeStrategy {
        DEFAULT (new VectorizeImpl());

        private final VectorizeStrategy INSTANCE;

        ConcreteStrategy(VectorizeStrategy concreteStrategy) {
            INSTANCE = concreteStrategy;
        }

        @Override
        public VectorImageGridIntersections processImage(MarvinImage img) {
            return INSTANCE.processImage(img);
        }
    }

    /**
     * Should perform edge Detection in order to have lines, that can be vectorized.
     * 
     * @param img An Image suitable for edge detection.
     * 
     * @return the VectorImageGridIntersections representing img's vectors 
     * intersections with the grids.
     */
    VectorImageGridIntersections processImage(MarvinImage img);
}

The fact that the enum implements the strategy is convenient to allow the enum class to act as proxy for its enclosed Instance. which also implements the interface.

it's a sort of strategyEnumProxy :P the clent code looks like this:

VectorizeStrategy.ConcreteStrategy.DEFAULT.processImage(img);

If it didn't implement the interface it'd had been:

VectorizeStrategy.ConcreteStrategy.DEFAULT.getInstance().processImage(img);
juanmf
  • 2,002
  • 2
  • 26
  • 28