Elija un valor aleatorio de una enumeración?

Si tengo una enumeración como esta:

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

¿Cuál es la mejor manera de elegir uno al azar? No es necesario que sea de calidad de producción a prueba de balas, pero una distribución bastante uniforme sería agradable.

Podría hacer algo como esto

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

Pero hay una manera mejor? Siento que esto es algo que ya ha sido resuelto.

Lo único que sugeriría es almacenar en caché el resultado de los values() porque cada llamada copia una matriz. Además, no crees un Random cada vez. Conserva uno. Aparte de eso, lo que estás haciendo está bien. Asi que:

 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)); } } 

Un único método es todo lo que necesita para todas sus enumeraciones aleatorias:

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

Que usarás:

 randomEnum(MyEnum.class); 

También prefiero usar SecureRandom como:

 private static final SecureRandom random = new SecureRandom(); 

Combinando las sugerencias de cletus y 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)]; } } } 

Editar: Vaya, olvidé el parámetro de tipo delimitado, > .

Linea sola

 return Letter.values()[new Random().nextInt(Letter.values().length)]; 

De acuerdo con Stphen C & helios. Una mejor forma de obtener elementos aleatorios de Enum es:

 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)]; 

Si hace esto para probar, puede usar Quickcheck ( este es un puerto Java en el que he estado trabajando ).

 import static net.java.quickcheck.generator.PrimitiveGeneratorSamples.*; TimeUnit anyEnumValue = anyEnumValue(TimeUnit.class); //one value 

Es compatible con todos los tipos primitivos, composición de tipo, colecciones, diferentes funciones de distribución, límites, etc. Tiene soporte para corredores que ejecutan múltiples valores:

 import static net.java.quickcheck.generator.PrimitiveGeneratorsIterables.*; for(TimeUnit timeUnit : someEnumValues(TimeUnit.class)){ //..test multiple values } 

La ventaja de Quickcheck es que puede definir pruebas basadas en una especificación donde TDD simple funciona con escenarios.

Probablemente sea más fácil tener una función para elegir un valor aleatorio de una matriz. Esto es más genérico y es fácil de llamar.

  T randomValue(T[] values) { return values[mRandom.nextInt(values.length)]; } 

Llamar así:

 MyEnum value = randomValue(MyEnum.values()); 

Esta es probablemente la forma más concisa de lograr su objective. Todo lo que necesita hacer es llamar a Letter.getRandom() y obtendrá una carta enum al azar.

 public enum Letter { A, B, C, //... public static Letter getRandom() { return values()[(int) (Math.random() * values().length)]; } } 

Yo usaría esto:

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

Es más fácil implementar una función aleatoria en la enumeración.

 public enum Via { A, B; public static Via viaAleatoria(){ Via[] vias = Via.values(); Random generator = new Random(); return vias[generator.nextInt(vias.length)]; } } 

y luego lo llamas de la clase que lo necesitas así

 public class Guardia{ private Via viaActiva; public Guardia(){ viaActiva = Via.viaAleatoria(); } 

Aquí una versión que usa shuffle y streams

 List letters = Arrays.asList(Direction.values()); Collections.shuffle(letters); return letters.stream().findFirst().get();