Java: выберите случайное значение из перечисления?

Если у меня есть перечисление вроде этого:

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

Каков наилучший способ выбрать один случайным образом? Это не обязательно должно быть качество продукции пуленепробиваемое, но довольно ровное распределение было бы приятным.

Я мог бы сделать что-то вроде этого

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

Но есть ли лучший способ? Я чувствую, что это то, что было решено раньше.

Ответ 1

Единственное, что я хотел бы предложить, - это кэшировать результат 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

Единственный метод - это все, что вам нужно для всех ваших случайных перечислений:

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

Что вы будете использовать:

randomEnum(MyEnum.class);

Я также предпочитаю использовать SecureRandom как:

private static final SecureRandom random = new SecureRandom();

Ответ 3

Объединив предложения cletus и helios,

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> {

        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>.

Ответ 4

Одиночная строка

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

Ответ 5

Согласитесь с 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)];
  }
}

Ответ 6

Letter lettre = Letter.values()[(int)(Math.random()*Letter.values().length)];

Ответ 7

Если вы сделаете это для тестирования, вы можете использовать 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 работает со сценариями.

Ответ 8

Вероятно, проще всего иметь функцию для выбора случайного значения из массива. Это более общее и простое вызов.

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

Вызываем так:

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

Ответ 9

Это eaiser для реализации случайной функции на перечислении.

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

Ответ 10

Здесь версия, в которой используются тасование и потоки

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

Ответ 11

Это, вероятно, самый сжатый способ достижения вашей цели. Все, что вам нужно сделать, это позвонить Letter.getRandom(), и вы получите случайное письмо с перечислением.

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

    public static Letter getRandom() {
        return values()[(int) (Math.random() * values().length)];
    }
}

Ответ 12

Я бы использовал это:

private static Random random = new Random();

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