Как сгенерировать случайное целое число в заданном диапазоне в Java
Простейшим способом получения целого числа в заданном диапазоне можно считать следующий:
public static int getRandBetween(int min, int max) { return min + new Random().nextInt(max - min + 1);}
Здесь и далее, мы выносим все проверки исходных данных за скобки, предполагая, что минимум всегда меньше максимума, а также величины достаточно далеки от максимального и минимального значения int'а, так что у нас нет проблемы перехода этих границ при проведении арифметических операций.
Вообще выше приведено довольно грубое использование класса Random, поскольку оно игнорирует ряд его примечательных возможностей.
В первую очередь -- это возможность задать начальное зерно (seed) для последующей генерации чисел. Наличие зерна позволяет генерировать всегда одинаковую последовательность псевдослучайных чисел, что может быть крайне полезно в целях отладки. Например:
public class RandExample {
static Random random = new Random(0L);
public static void main(String[] args) { for (int i = 0; i < 3; i++) { System.out.println(getRandBetween(1, 100)); } }
public static int getRandBetween(int min, int max) { return min + random.nextInt(max - min + 1); }}
На моей машине каждый перезапуск этой программы выводит в консоль одну и ту же последовательность чисел: 61, 49, 30.
Закончив отладку, можно исключить зерно из кода программы.
Начиная с версии Java 8 класс Random позволяет получить поток (IntStream) псевдослучайных целых для последующей обработки. Например, следующий код будет выводить в консоль псевдослучайные целые числа до тех пор, пока исполнение программы не будет прервано вручную:
random.ints().forEach(System.out::println);
Разумеется, на поток можно наложить ограничения. Например:
random.ints(10).forEach(System.out::println);
выведет в консоль уже всего 10 целых чисел, а
random.ints(10, 1, 11).forEach(System.out::println);
выведет в консоль 10 целых чисел в диапазоне от 1 до 10-ти, что нам и требовалось изначально. Из примера видно, максимум задаётся, как максимально необходимое число + 1, и в документации отмечено, что передаваемая параметром верхняя граница исключается (exclusive).
Аналогично метод doubles() позволяет получить (и ограничить) поток псевдослучайных чисел типа double (DoubleStream).
Начиная с Java 7 для получения псевдослучайных целых в определённом диапазоне, можно получить отдельный Random для каждого потока:
Random safeRandom = ThreadLocalRandom.current();
Так как если использовать один экземпляр Random для нескольких потоков, на них всех будет приходится одно зерно. Это в силу специфики реализации класса Random может приводить к ухудшению производительности. Решением является использование класса ThreadLocalRandom, который наследует Random со всеми его методами, но не имеет указанной проблемы.
Класс Math имеет метод random(), который возвращает случайный double в диапазоне от 0.0 до 1.0. Это значение вполне можно привести к требуемому диапазону целых, например так:
public static int getRandBetween(int min, int max) { return min + (int)(Math.random() * ((max - min) + 1));}
Однако, следует отметить, что этот метод банально использует nextDouble() отдельного экземпляра Random. И как генератор псевдослучайных чисел ничем особо не интересен.
private static final class RandomNumberGeneratorHolder { static final Random randomNumberGenerator = new Random();}
public static double random() { return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();}
public static int getRandBetween(int min, int max) { return min + new Random().nextInt(max - min + 1);}
Здесь и далее, мы выносим все проверки исходных данных за скобки, предполагая, что минимум всегда меньше максимума, а также величины достаточно далеки от максимального и минимального значения int'а, так что у нас нет проблемы перехода этих границ при проведении арифметических операций.
Использование класса Random
Использование класса Random
Вообще выше приведено довольно грубое использование класса Random, поскольку оно игнорирует ряд его примечательных возможностей.
В первую очередь -- это возможность задать начальное зерно (seed) для последующей генерации чисел. Наличие зерна позволяет генерировать всегда одинаковую последовательность псевдослучайных чисел, что может быть крайне полезно в целях отладки. Например:
public class RandExample {
static Random random = new Random(0L);
public static void main(String[] args) { for (int i = 0; i < 3; i++) { System.out.println(getRandBetween(1, 100)); } }
public static int getRandBetween(int min, int max) { return min + random.nextInt(max - min + 1); }}
На моей машине каждый перезапуск этой программы выводит в консоль одну и ту же последовательность чисел: 61, 49, 30.
Закончив отладку, можно исключить зерно из кода программы.
Начиная с версии Java 8 класс Random позволяет получить поток (IntStream) псевдослучайных целых для последующей обработки. Например, следующий код будет выводить в консоль псевдослучайные целые числа до тех пор, пока исполнение программы не будет прервано вручную:
random.ints().forEach(System.out::println);
Разумеется, на поток можно наложить ограничения. Например:
random.ints(10).forEach(System.out::println);
выведет в консоль уже всего 10 целых чисел, а
random.ints(10, 1, 11).forEach(System.out::println);
выведет в консоль 10 целых чисел в диапазоне от 1 до 10-ти, что нам и требовалось изначально. Из примера видно, максимум задаётся, как максимально необходимое число + 1, и в документации отмечено, что передаваемая параметром верхняя граница исключается (exclusive).
Аналогично метод doubles() позволяет получить (и ограничить) поток псевдослучайных чисел типа double (DoubleStream).
Многопоточные приложения
Многопоточные приложения
Начиная с Java 7 для получения псевдослучайных целых в определённом диапазоне, можно получить отдельный Random для каждого потока:
Random safeRandom = ThreadLocalRandom.current();
Так как если использовать один экземпляр Random для нескольких потоков, на них всех будет приходится одно зерно. Это в силу специфики реализации класса Random может приводить к ухудшению производительности. Решением является использование класса ThreadLocalRandom, который наследует Random со всеми его методами, но не имеет указанной проблемы.
Класс Math
Класс Math
Класс Math имеет метод random(), который возвращает случайный double в диапазоне от 0.0 до 1.0. Это значение вполне можно привести к требуемому диапазону целых, например так:
public static int getRandBetween(int min, int max) { return min + (int)(Math.random() * ((max - min) + 1));}
Однако, следует отметить, что этот метод банально использует nextDouble() отдельного экземпляра Random. И как генератор псевдослучайных чисел ничем особо не интересен.
private static final class RandomNumberGeneratorHolder { static final Random randomNumberGenerator = new Random();}
public static double random() { return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();}