如果我有一个这样的enum:

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

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

我可以这样做

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

但是有没有更好的办法呢?我觉得这个问题之前已经解决了。


当前回答

我唯一的建议是缓存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));
  }
}

其他回答

同意stephen C和helios的观点。从Enum中获取随机元素的更好方法是:

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

  private static final Letter[] VALUES = values();
  private static final int SIZE = VALUES.length;
  private static final Random RANDOM = new Random();

  public static Letter getRandomLetter()  {
    return VALUES[RANDOM.nextInt(SIZE)];
  }
}

一个方法就是你需要的所有随机枚举:

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

你会用到:

randomEnum(MyEnum.class);

我也更喜欢使用securerrandom:

private static final SecureRandom random = new SecureRandom();
public static Letter randomLetter() {
    return List.of(values()).get(Random.randomInt(List.of(values()).size()));

}

简单的Kotlin解决方案

MyEnum.values().random()

random()是Collection对象上包含在基本Kotlin中的默认扩展函数。Kotlin文档链接

如果你想用扩展函数来简化它,试试这个:

inline fun <reified T : Enum<T>> random(): T = enumValues<T>().random()

// Then call
random<MyEnum>()

使它在枚举类上是静态的。确保在枚举文件中导入my.package.random

MyEnum.randomValue()

// Add this to your enum class
companion object {
    fun randomValue(): MyEnum {
        return random()
    }
}

如果您需要从枚举的实例执行此操作,请尝试此扩展

inline fun <reified T : Enum<T>> T.random() = enumValues<T>().random()

// Then call
MyEnum.VALUE.random() // or myEnumVal.random() 

我会用这个:

private static Random random = new Random();

public Object getRandomFromEnum(Class<? extends Enum<?>> clazz) {
    return clazz.values()[random.nextInt(clazz.values().length)];
}