Java:从枚举中选择一个随机值?

问题

如果我有这样的枚举:

public enum Letter {
    A,
    B,
    C,
    //...
}

随机选择一个的最佳方法是什么?它不需要是生产质量的防弹,但相当均匀的分布将是不错的。

我可以做这样的事情

private Letter randomLetter() {
    int pick = new Random().nextInt(Letter.values().length);
    return Letter.values()[pick];
}

但有更好的方法吗?我觉得这是以前已经解决的问题。


#1 热门回答(114 赞)

我唯一建议的是缓存values()的结果,因为每次调用都会复制一个数组。另外,不要每次都创建一个Random。保持一个。除此之外,你正在做的事情很好。所以:

public enum Letter {
  A,
  B,
  C,
  //...

  private static final List<Letter> VALUES =
    Collections.unmodifiableList(Arrays.asList(values()));
  private static final int SIZE = VALUES.size();
  private static final Random RANDOM = new Random();

  public static Letter randomLetter()  {
    return VALUES.get(RANDOM.nextInt(SIZE));
  }
}

#2 热门回答(87 赞)

所有随机枚举都需要一种方法:

public static <T extends Enum<?>> T randomEnum(Class<T> clazz){
        int x = random.nextInt(clazz.getEnumConstants().length);
        return clazz.getEnumConstants()[x];
    }

你将使用哪个:

randomEnum(MyEnum.class);

我也更喜欢使用SecureRandomas:

private static final SecureRandom random = new SecureRandom();

#3 热门回答(37 赞)

结合cletus和2889489083的建议,

import java.util.Random;

public class EnumTest {

    private enum Season { WINTER, SPRING, SUMMER, FALL }

    private static final RandomEnum<Season> r =
        new RandomEnum<Season>(Season.class);

    public static void main(String[] args) {
        System.out.println(r.random());
    }

    private static class RandomEnum<E extends Enum<E>> {

        private static final Random RND = new Random();
        private final E[] values;

        public RandomEnum(Class<E> token) {
            values = token.getEnumConstants();
        }

        public E random() {
            return values[RND.nextInt(values.length)];
        }
    }
}

编辑:哎呀,我忘了有界类型参数,<E extends Enum<E>>