【问题标题】:Is there any reason to override methods in enums in Java 8是否有任何理由覆盖 Java 8 中的枚举中的方法
【发布时间】:2015-02-02 12:14:32
【问题描述】:

正如here 指出的那样,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 中使用方法覆盖,还是应该始终首选功能接口?

【问题讨论】:

  • 我认为第一个代码中应该是public int operate...
  • 你可以有很多方法,在一个枚举中互相调用。它们的签名可能与任何标准功能接口都不匹配。顺便说一句,在您的第一个 sn-p 中,您的操作()方法应该被声明为抽象的,而不是提供一个实现。
  • 另一种方式(在您的具体示例中)是enum Operator implements BinaryOperator&lt;Integer&gt;,然后直接实现apply
  • 我喜欢你的 lambdas 解决方案,它看起来比方法覆盖干净得多。
  • 顺便说一句,你可以使用接口来实现这个逻辑。

标签: java enums java-8


【解决方案1】:

如果您查看this answer,它总结了在此enum 场景中使用 lambda 表达式的优势,您可能会注意到这些优势在 Java 8 之前的变体中都消失了。它既不比旧的专用 enum 变体更具可读性,也没有提高性能。此外,interface BinaryOperator 在 Java 8 之前不存在,因此它是您需要添加到代码库中才能遵循这种方法的另一个类。

在 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 中进行搜索!话虽如此,我不确定你是否真的回答了我的问题。我不是在问新方法是否更好(我相信是),而是在问是否有任何理由覆盖枚举中的方法?
  • 我已经编辑了这个问题,以便更清楚地说明我在问什么。
  • 这是一个合理的答案,但可以使用为字段分配默认 lambda 的空构造函数来轻松实现默认行为。
  • @sprinter:当然,你可以同时实现这两个例子。这不会是错的。只是在一种情况下,委托风格在可读性和启动时间方面产生了优势,而在另一种情况下,覆盖风格领先了一小步。这并不是说我们在谈论基本规则。 “我会一直这样做”也是一个合理的原则。 (虽然我更喜欢的原则是“我迟早会质疑它,即使是我自己的代码”)
  • 我喜欢你最后的原则!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-18
  • 2011-08-31
  • 1970-01-01
相关资源
最近更新 更多