8

As pointed out here lambdas provide a quite elegant way of specifying behaviour for individual enum values.

Before Java 8 I would normally have implemented this as:

enum Operator {
    TIMES {
        public int operate(int n1, int n2) {
            return n1 * n2;
        }
    },
    PLUS {
        public int operate(int n1, int n2) {
            return n1 + n2;
        }
    };

    public int operate(int n1, int n2) {
        throw new AssertionError();
    }            
}

Now I tend to use:

enum Operator {
    TIMES((n1, n2) -> n1 * n2),
    PLUS((n1, n2) -> n1 + n2);

    private final BinaryOperator<Integer> operation;

    private Operator(BinaryOperator<Integer> operation) {
        this.operation = operation;
    }

    public int operate(int n1, int n2) {
        return operation.apply(n1, n2);
    }
}

This seems significantly more elegant.

I cannot think of a reason to override methods for a specific enum value now. So my question is, are there any good reasons to use method overrides in an enum now or should a functional interface always be preferred?

Community
  • 1
  • 1
sprinter
  • 27,148
  • 6
  • 47
  • 78
  • 1
    I think that should be `public int operate` in the first code... – tobias_k Feb 02 '15 at 12:18
  • You could have many methods, calling each other, in an enum. And their signature might not match with any of the standard functional interfaces. BTW, in your first snippet, your operate() method should be declared abstract rather than provide an implementation. – JB Nizet Feb 02 '15 at 12:19
  • Another way (in your specific example) would be `enum Operator implements BinaryOperator` and then implement `apply` directly. – tobias_k Feb 02 '15 at 12:22
  • I like your solution with lambdas, it looks much cleaner than method overrides. – Jesper Feb 02 '15 at 12:29
  • btw, you could implement this logic, using interface. – Ivan Feb 02 '15 at 12:39
  • possible duplicate of [Lambdas in the classical Operation enum example](http://stackoverflow.com/questions/23361418/lambdas-in-the-classical-operation-enum-example) – tobias_k Feb 02 '15 at 14:37

1 Answers1

6

If you look at this answer which summarizes the advantages of using lambda expression in this enum scenario you might notice that these advantages all disappear in the pre-Java 8 variant. It’s neither more readable than the old specialized enum variant nor does it improve the performance. Further, the interface BinaryOperator doesn’t exist before Java 8 so it’s another class you would need to add to your codebase to follow this approach.

The main reason to use this delegation approach in pre-Java 8 code would be to ease the migration if you plan to switch to Java 8 soon.


Update to your updated question:

If you mainly focus on the Java 8 use case, I would recommend to always use the delegation approach when all enum cases have a different behavior which still follows a similar pattern which can benefit from using lambda expressions, as it’s the case when implementing operators like in your example.

A counter-example would be an enum where most of them share a common behavior that will be overridden for one or a few cases only. E.g.:

enum Tokens {
    FOO, BAR, BAZ, AND, A, LOT, MORE // etc …

    /** Special Token End-Of-File */
    EOF {
        @Override
        public boolean matches(String input, int pos) {
            return input.length()==pos;
        }
    };

    // all ordinary tokens have the same behavior
    public boolean matches(String input, int pos) {
        return input.length()-pos >= name().length()
          && input.regionMatches(pos, name(), 0, name().length());
    }
}
Community
  • 1
  • 1
Holger
  • 285,553
  • 42
  • 434
  • 765
  • Thanks for this. I hadn't found that answer before posting this - I really can't seem to get searching working in SO! Having said that I'm not sure you're really answering my question. I'm not asking whether the new way is better (I believe it is) but whether there's any reason to ever override methods in enums? – sprinter Feb 02 '15 at 12:52
  • I've edited the question to make it a bit clearer what I am asking. – sprinter Feb 02 '15 at 13:01
  • That's a reasonable answer but default behaviour could be implemented just as easily with an empty constructor that assigns a default lambda to the field. – sprinter Feb 02 '15 at 20:47
  • 1
    @sprinter: of course, you can implement both examples both ways. And it wouldn’t be wrong. It’s only that in one case the delegation style yields an advantage in readability and startup time while in the other case the override style is one small step ahead. It’s not that we were talking about fundamental rules. “I’ll do it always the same way” would also a reasonable principle. (Though my preferred principle is “I’ll question it, sooner or later, even if it’s my own code”) – Holger Feb 03 '15 at 08:46
  • I like your last principle! – sprinter Feb 03 '15 at 09:44