Java 8中枚举类中是否有重写方法的必要性?

8

正如在这里指出的那样,lambda表达式为指定每个枚举值的行为提供了一种非常优雅的方式。

在Java 8之前,我通常会以以下方式实现:

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();
    }            
}

现在我倾向于使用:

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);
    }
}

这看起来更加优美。

我现在想不到为一个特定的枚举值而重写方法的原因。所以我的问题是,在 enum 中使用方法重写有没有好的理由,或者应该总是优先考虑使用函数接口?


1
我认为第一段代码应该是 public int operate... - tobias_k
在枚举中,您可以有许多相互调用的方法。它们的签名可能与任何标准功能接口都不匹配。顺便说一句,在您的第一个片段中,您的operate()方法应该声明为抽象而不是提供实现。 - JB Nizet
另一种方法(在您的特定示例中)是 enum Operator implements BinaryOperator<Integer>,然后直接实现 apply - tobias_k
我喜欢你用 Lambda 的解决方案,看起来比方法覆盖更加简洁。 - Jesper
顺便说一下,你可以使用接口来实现这个逻辑。 - Ivan
可能是Lambdas in the classical Operation enum example的重复内容。 - tobias_k
1个回答

6
如果您看一下这个答案,它总结了在这种enum场景中使用lambda表达式的优点,您可能会注意到这些优点在Java 8之前的版本中都消失了。它既不比旧的专门的enum变体更易读,也不会提高性能。此外,Java 8之前不存在interface BinaryOperator,因此这是另一个你需要添加到你的代码库中的类来遵循这种方法。
在Java 8之前的代码中使用这种委托方法的主要原因是为了在不久的将来切换到Java 8时方便迁移。
更新到您更新的问题:
如果您主要关注Java 8的用例,当所有enum情况具有不同的行为,但仍遵循可以受益于使用lambda表达式的类似模式时,我建议始终使用委托方法,就像在实现运算符时的情况一样。
反例是一个enum,其中大多数都共享相同的行为,并且只会为一个或几个案例重写。例如:
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());
    }
}

谢谢你。在发布这个问题之前,我没有找到那个答案 - 我似乎真的无法让SO的搜索工作!话虽如此,我不确定你是否真正回答了我的问题。我不是在问新方法是否更好(我相信它是),而是是否有任何理由覆盖枚举中的方法? - sprinter
我已经编辑了问题,以使我的问题更加清晰明了。 - sprinter
这是一个合理的答案,但是默认行为也可以通过使用空构造函数并将默认 lambda 分配给字段来轻松实现。 - sprinter
1
@sprinter:当然,你可以用两种方式实现这两个例子。都没问题。只是在一种情况下,委托样式在可读性和启动时间方面具有优势,而在另一种情况下,覆盖样式稍微领先一步。并不是我们在谈论基本规则。 "我总是以同样的方式做" 也是一个合理的原则。(虽然我的首选原则是“即使是我的代码,我迟早也会质疑它”) - Holger
我喜欢你的最后原则! - sprinter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接