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

What's the best way to implement `next` and `previous` on an enum type?

假设我有一个枚举:

1
2
3
enum E {
    A, B, C;
}

如lucasmo在此答案中所示,枚举值按初始化顺序存储在静态数组中,以后您可以使用E.values()检索此数组(的克隆)。

现在,假设我要实现E#getNextE#getPrevious,以使以下所有表达式求和为true

1
2
3
4
5
6
7
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

我当前对getNext的实现如下:

1
2
3
4
5
6
7
8
9
public E getNext() {
    E[] e = E.values();
    int i = 0;
    for (; e[i] != this; i++)
        ;
    i++;
    i %= e.length;
    return e[i];
}

getPrevious的类似方法。

但是,此代码充其量似乎很麻烦(例如,"空" for循环,可争论的滥用计数器变量,最坏的情况下可能是错误的(可能是反射)。

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

注意:我不希望这个问题是主观的。 我对"最佳"实施的要求是要求最快,最清洁和最可维护的实施的简写。


尝试这个:

1
2
3
4
5
6
7
public static enum A {
    X, Y, Z;
    private static A[] vals = values();
    public A next()
    {
        return vals[(this.ordinal()+1) % vals.length];
    }

previous()的实现留作练习,但是请记住,在Java中,模a % b可以返回负数。

编辑:根据建议,制作values()数组的私有静态副本,以避免每次调用next()previous()时复制数组。


或者,可以按照以下思路进行某种方式的选择:

1
2
3
4
5
6
7
8
9
10
11
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();
  }
}

笔记:

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