在枚举类型上实现`next`和`previous`的最佳方法是什么?

wch*_*gin 53 java optimization enums

假设我有一个枚举:

enum E {
    A, B, C;
}
Run Code Online (Sandbox Code Playgroud)

正如所示这个答案lucasmo,枚举值存储在它们初始化的顺序静态数组,你可以在以后检索(的克隆)这个数组E.values().

现在假设我想要实现E#getNext并且E#getPrevious以下所有表达式都评估为true:

E.A.getNext() == E.B
E.B.getNext() == E.C
E.C.getNext() == E.A

E.A.getPrevious() == E.C
E.B.getPrevious() == E.A
E.C.getPrevious() == E.B
Run Code Online (Sandbox Code Playgroud)

我目前的实施getNext如下:

public E getNext() {
    E[] e = E.values();
    int i = 0;
    for (; e[i] != this; i++)
        ;
    i++;
    i %= e.length;
    return e[i];
}
Run Code Online (Sandbox Code Playgroud)

和类似的方法getPrevious.

然而,这段代码充其量似乎很麻烦(例如,"空" for循环,可论证滥用计数器变量,并且最坏的可能是错误的(可能反思).

在Java 7中实现枚举类型的最佳方法getNextgetPrevious方法是什么?


注意:打算这个问题是主观的.我对"最佳"实现的请求是要求实施最快,最干净,最易维护的简写.

Jim*_*son 82

试试这个:

public static enum A { 
    X, Y, Z;
    private static A[] vals = values();
    public A next()
    {
        return vals[(this.ordinal()+1) % vals.length];
    }
Run Code Online (Sandbox Code Playgroud)

实现previous()仍然是一个练习,但回想一下,在Java中,模数a % b可以返回负数.

编辑:建议,制作values()数组的私有静态副本,以避免每次都进行数组复制next()或被previous()调用.

  • 当您可以执行`A.values()[0] = null`或`A.values()[0] = AZ`并将其他所有内容弄清楚时,Singleton无关紧要.仅仅因为数组是最终的并不意味着它的内容是. (4认同)
  • 啊! 我不知道“普通”。我寻找了`indexOf`。声明`A [] values = values()`以避免克隆两次会更好吗? (2认同)

Gho*_*ica 7

或者,可以按照以下想法的方式进行:

public enum SomeEnum {
  A, B, C;

  public Optional<SomeEnum> next() {
    switch (this) {
      case A: return Optional.of(B);
      case B: return Optional.of(C);
      // any other case can NOT be mapped!
      default: return Optional.empty();
  }
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  1. 与其他答案相反,这种方式做了一些隐式映射; 而不是依靠ordinal().当然这意味着更多的代码; 但它也迫使作者考虑添加新常量或删除现有常量的含义.当依赖序数时,您隐含的假设是该顺序基于枚举常量声明所使用的顺序.因此,当有人在6个月后回来并且必须添加一个新的常量时,他必须明白新的常数Y需要X, Y, Z...而不是仅仅追加X, Z, Y!
  2. 可能存在这样的情况:"最后"枚举常量使"第一"作为后继者没有任何意义.以T恤尺码为例.XXL.next()肯定不是XS.对于这种情况,使用Optional是更合适的答案.