从枚举中选择一个随机值?
如果我有这样的枚举:
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 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)); } }
所有随机枚举都需要一种方法:
public static > T randomEnum(Class clazz){ int x = random.nextInt(clazz.getEnumConstants().length); return clazz.getEnumConstants()[x]; }
您将使用哪个:
randomEnum(MyEnum.class);
我也更喜欢使用SecureRandom :
private static final SecureRandom random = new SecureRandom();
结合cletus和helios的建议,
import java.util.Random; public class EnumTest { private enum Season { WINTER, SPRING, SUMMER, FALL } private static final RandomEnum r = new RandomEnum (Season.class); public static void main(String[] args) { System.out.println(r.random()); } private static class RandomEnum> { private static final Random RND = new Random(); private final E[] values; public RandomEnum(Class token) { values = token.getEnumConstants(); } public E random() { return values[RND.nextInt(values.length)]; } } }
编辑:糟糕,我忘记了有界类型参数,
。
单线
return Letter.values()[new Random().nextInt(Letter.values().length)];
同意Stphen 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)]; } }
Letter lettre = Letter.values()[(int)(Math.random()*Letter.values().length)];
如果你这样做进行测试,可以使用Quickcheck ( 这是我一直在研究的Java端口 )。
import static net.java.quickcheck.generator.PrimitiveGeneratorSamples.*; TimeUnit anyEnumValue = anyEnumValue(TimeUnit.class); //one value
它支持所有原始类型,类型组合,集合,不同的分布函数,边界等。它支持执行多个值的运行程序:
import static net.java.quickcheck.generator.PrimitiveGeneratorsIterables.*; for(TimeUnit timeUnit : someEnumValues(TimeUnit.class)){ //..test multiple values }
Quickcheck的优点是您可以根据简单TDD与场景一起使用的规范来定义测试。
拥有一个从数组中选择随机值的函数可能是最简单的。 这更通用,并且可以直接调用。
T randomValue(T[] values) { return values[mRandom.nextInt(values.length)]; }
像这样打电话:
MyEnum value = randomValue(MyEnum.values());
这是一个使用shuffle和流的版本
List letters = Arrays.asList(Direction.values()); Collections.shuffle(letters); return letters.stream().findFirst().get();
这可能是实现目标的最简洁方式。您需要做的就是调用Letter.getRandom()
,您将获得一个随机的枚举字母。
public enum Letter { A, B, C, //... public static Letter getRandom() { return values()[(int) (Math.random() * values().length)]; } }
在枚举上实现随机函数是更好的做法。
public enum Via { A, B; public static Via viaAleatoria(){ Via[] vias = Via.values(); Random generator = new Random(); return vias[generator.nextInt(vias.length)]; } }
然后你就像这样从你需要它的类中调用它
public class Guardia{ private Via viaActiva; public Guardia(){ viaActiva = Via.viaAleatoria(); }
我会用这个:
private static Random random = new Random(); public Object getRandomFromEnum(Class extends Enum>> clazz) { return clazz.values()[random.nextInt(clazz.values().length)]; }