使用枚举序号是一种好习惯吗?

问题描述 投票:28回答:9

我有一个枚举:

public enum Persons {

    CHILD,
    PARENT,
    GRANDPARENT;

}

使用ordinal()方法检查枚举成员之间的“层次结构”是否存在问题?我的意思是-使用它时,除了冗长之外,还有什么缺点吗?将来有人可能会意外更改顺序。

或者做这样的事更好:

public enum Persons {

    CHILD(0),
    PARENT(1),
    GRANDPARENT(2);

    private Integer hierarchy;

    private Persons(final Integer hierarchy) {
        this.hierarchy = hierarchy;
    }

    public Integer getHierarchy() {
        return hierarchy;
    }

}
java enums coding-style verbose
9个回答
48
投票

TLDR:不,你不应该!

如果您在ordinal中引用Javadoc的Enum.java方法:

大多数程序员都不会使用此方法。它是设计供基于枚举的复杂数据结构使用,例如分别为java.util.EnumSetjava.util.EnumMap

首先-阅读手册(在这种情况下为Javadoc)。

第二-不要写易碎的代码。枚举值将来可能会更改,您的第二个代码示例将更多地[maintainable

[如果在PARENTGRANDPARENT之间插入一个新的枚举值,则绝对不会为将来带来麻烦。

12
投票

第一种方法不容易理解,因为您必须阅读使用枚举来理解枚举顺序很重要的代码。这很容易出错。

public enum Persons { CHILD, PARENT, GRANDPARENT; }

第二种方式

更好,因为它是自我解释CHILD(0), PARENT(1), GRANDPARENT(2); private SourceType(final Integer hierarchy) { this.hierarchy = hierarchy; }

当然,枚举值的顺序应与枚举构造函数参数提供的层次顺序一致。

它引入了一种冗余

,因为枚举值和枚举构造函数的参数都传达了它们的层次结构。但是为什么会有问题?枚举旨在表示恒定且不经常更改的值。OP枚举用法很好地说明了良好的枚举用法:CHILD, PARENT, GRANDPARENT
枚举不是为了表示经常移动的值。在这种情况下,使用枚举可能不是最佳选择,因为它可能会频繁破坏使用该枚举的客户端代码,并且在每次修改枚举值时,它都会强制重新编译,重新打包和重新部署应用程序。

10
投票
正如Joshua Bloch在

Effective Java中所建议的那样,从其序数派生与枚举关联的值不是一个好主意,因为更改枚举值的顺序可能会破坏您编码的逻辑。

您提到的第二种方法完全遵循作者的建议,即将值存储在单独的字段中。

我想说,您建议的替代方案肯定更好,因为它在扩展枚举值的顺序和层次结构的概念时更加可扩展和可维护。


8
投票
首先,您甚至可能不需要数字顺序值-那是什么Comparable是为Comparable实现的。

如果您

do由于某种原因需要数字顺序值,是的,您应该使用Enum<E>。这就是它的用途。

Java Comparable<E>的标准做法是按声明顺序排序,这就是ordinal()实现Enums的原因,以及为什么Enum<E>Comparable<E>

如果您添加自己的不使用的非标准比较代码,Enum.compareTo()并且不依赖于声明顺序,您只是会使其他试图使用您的代码的人感到困惑,包括你自己未来的自我。没有人会期望该代码存在。他们将期望finalComparable

如果自定义订单与声明订单不符,则任何人看着宣言会很困惑。如果

确实

(此刻正要)符合声明顺序,任何人看着它会期待这一点,他们将在某个将来的日期没有收到令人讨厌的震惊。 (如果您写代码(或测试)以确保定制订单与声明顺序,您只是在增强它的不必要性。)如果添加您自己的订单价值,您将在维护方面感到头疼为自己:

    您需要确保您的Enum值是唯一的
  1. 如果在中间添加一个值,则需要重新编号全部后续值
  • [如果您担心有人会意外更改订单,将来,编写一个检查订单的单元测试。

    总而言之,用Enum的不朽字眼:

    了解并使用库


  • P.S。另外,当您指的是hierarchy时,请勿使用Item 47。 🙂

    6
    投票
    不建议使用Integer,因为枚举声明中的更改可能会影响顺序值。

    UPDATE:

    值得注意的是,枚举字段是常量,并且可以具有重复的值,即

    int

    根据您打算对ordinal()进行的处理,可能有害或有益。

    此外,例如,您可以使用枚举常量来构建自己的enum Family { OFFSPRING(0), PARENT(1), GRANDPARENT(2), SIBLING(3), COUSING(4), UNCLE(4), AUNT(4); private final int hierarchy; private Family(int hierarchy) { this.hierarchy = hierarchy; } public int getHierarchy() { return hierarchy; } } 而不是使用hierarchy


    5
    投票
    如果只想在枚举值之间创建关系,则可以使用

    其他枚举值:

    EnumFlags
    请注意,您只能使用在您要声明的值之前按词法声明的枚举值,因此,仅当您的关系形成一个无环有向图(并且声明它们的顺序是有效的拓扑排序)时,此方法才有效。 

    3
    投票
    我将使用您的第二个选项(使用显式整数),因此数值是由您而不是由Java分配的。

    1
    投票
    根据java EnumSet

    返回此枚举常数的序数(其在枚举声明,其中初始常量分配为的序数零)。大多数程序员都不会使用此方法。它是设计供基于枚举的复杂数据结构使用,例如EnumSet和EnumMap。

    您可以通过更改枚举的顺序来控制序数,但是不能明确设置它。一种解决方法是在枚举中为所需的数字提供一个额外的方法。

    public enum Person { GRANDPARENT(null), PARENT(GRANDPARENT), CHILD(PARENT); private final Person parent; private Person(Person parent) { this.parent = parent; } public final Parent getParent() { return parent; } }

    在这种情况下为doc,但为enum Mobile {
       Samsung(400), Nokia(250),Motorola(325);
    
       private final int val;
      private Mobile (int v) { val = v; }
      public int getVal() { return val; }
    }
    

    1
    投票
    这不是您问题的直接答案。对于您的用例而言,是一种更好的方法。这种方式确保了下一个开发人员将明确知道不应更改分配给属性的值。

    创建带有静态属性的类,它将模拟您的枚举:

    Samsung.ordinal() = 0

    然后像枚举一样使用:

    Samsung.getVal() = 400

    它将适用于大多数简单的用例。否则,您可能会缺少public class Persons {
        final public static int CHILD = 0;
        final public static int PARENT = 1;
        final public static int GRANDPARENT = 2;
    }
    Persons.CHILD
    valueOf()EnumSet之类的选项。
    © www.soinside.com 2019 - 2024. All rights reserved.