Math.random() в Java возвращает псевдослучайное число типа double в диапазоне от 0.0 (включительно) до 1.0 (исключительно). Чтобы сгенерировать целое число в заданном диапазоне (от min до max), используйте формулу: (int) (((max - min) + 1) * Math.random()) + min. Обе границы входят в диапазон: при min = 1 и max = 6 получится честный бросок кубика, то есть числа от 1 до 6 включительно. Хотя эта формула может показаться сложной, она очень проста в применении. Давайте разберем ее на практических примерах, начиная с основ и заканчивая использованием для реальных задач.

Кратко

  • Math.random() возвращает double от 0.0 включительно до 1.0 исключительно, то есть единицу не выдает никогда.
  • Метод статический и лежит в классе java.lang.Math, поэтому импорт не нужен.
  • Целое число от 0 до n-1 получают так: (int) (Math.random() * n), а произвольный диапазон через формулу с min и max.
  • Приведение к int отбрасывает дробную часть, а не округляет, поэтому в формуле и появляется + 1: без него верхняя граница выпадать не будет.
  • Числа псевдослучайные: их считает алгоритм, а не физический источник случайности. Для паролей, токенов и всего, что связано с безопасностью, этот метод не подходит.
  • Под капотом метод один раз создает общий генератор и дальше пользуется только им, зато он синхронизирован и безопасен при вызове из разных потоков.

Что такое метод Math.random() в Java?

Метод java.lang.Math.random() возвращает псевдослучайное число типа double в диапазоне от 0.0 до 1.0.
Метод живет в классе java.lang.Math рядом с остальной математикой, поэтому импортировать ничего не нужно, а его описание есть в документации Oracle. Следовательно, случайное число, сгенерированное с помощью встроенного метода Java, всегда находится в диапазоне от 0 до 1.
0.0 ≤ random < 1.0
Обратите внимание, что случайное число больше или равно 0.0 и меньше 1.0.

Как использовать Math.random() в Java?

Использовать метод Math.random() довольно просто даже для новичков.

Пример 1

Давайте рассмотрим базовый пример использования метода Math.random() в Java для ясного понимания.
public class RandomTest {

    public static void main(String[] args) {

        double random1 = Math.random();
        double random2 = Math.random();
        System.out.println("Первое случайное число: " + random1);
        System.out.println("Второе случайное число: " + random2);
    }
}

Вывод

Первое случайное число: 0.5486939400685561 Второе случайное число: 0.23550115674999972

Использование метода random() в заданном диапазоне

Вызов метода Math.random() кажется довольно очевидным. Однако наша потребность в случайных числах не всегда ограничивается диапазоном от 0 до 1. Для реальных задач мы можем работать и в других указанных диапазонах. Давайте рассмотрим пример использования метода Math.random() для заданного диапазона, скажем, от 1 до 6, как на игральном кубике (про другие способы получить число в диапазоне у нас есть отдельная статья).

Пример 2

public class RandomNumberInRange {
    public static int getRandom(int min, int max) {

        int range = (max - min) + 1;
        int random = (int) (range * Math.random()) + min;
        return random;
    }

    public static void main(String[] args) {
        // Давайте сыграем в Ludo с 4 игроками
        int dieRoll = getRandom(1, 6);
        System.out.println("Ход красных: " + dieRoll);

        dieRoll = getRandom(1, 6);
        System.out.println("Ход синих: " + dieRoll);

        dieRoll = getRandom(1, 6);
        System.out.println("Ход зеленых: " + dieRoll);

        dieRoll = getRandom(1, 6);
        System.out.println("Ход желтых: " + dieRoll);
    }
}

Вывод

Ход красных: 3 Ход синих: 2 Ход зеленых: 6 Ход желтых: 4

Объяснение

Чтобы получить случайное число в пределах диапазона, вам нужно вычислить диапазон, вычитая min из max. Затем диапазон умножают на Math.random(), результат приводят к int и только после этого прибавляют min. Порядок здесь важен. Если прибавить min до приведения, то при отрицательном min нижняя граница выпадать не будет: приведение к int отбрасывает дробную часть в сторону нуля, а не вниз. В остальном все просто: после приведения вы получаете случайное число в указанном диапазоне. Соберем типовые задачи в одну шпаргалку:
Задача Код Пояснение
Дробное число от 0 до 1 Math.random() единица не выпадет никогда
Целое от 0 до n-1 (int) (Math.random() * n) привычный диапазон индексов массива
Целое от min до max включительно (int) (((max - min) + 1) * Math.random()) + min та самая формула из начала статьи
Бросок кубика (int) (Math.random() * 6) + 1 частный случай формулы при min = 1 и max = 6
Случайный элемент массива array[(int) (Math.random() * array.length)] длина массива и есть верхняя граница
Случайное «да» или «нет» Math.random() < 0.5 примерно поровну в обе стороны

Когда Math.random() мало

Метод умеет ровно одно: выдавать дробное число от нуля до единицы. Для задач посложнее в стандартной библиотеке есть три специальных инструмента, и все они родственники: ThreadLocalRandom и SecureRandom наследуются от java.util.Random.
  • java.util.Random. Тот самый класс, экземпляр которого Math.random() создает внутри себя. У него есть методы под конкретные типы: nextInt(6) сразу дает целое от 0 до 5 без умножений и приведений, а с Java 17 работает и вариант с двумя границами, nextInt(1, 7). Еще этому классу можно передать зерно в конструктор и получать одну и ту же последовательность при каждом запуске, что незаменимо в тестах.
  • ThreadLocalRandom. Из пакета java.util.concurrent, доступен с Java 7. Документация Math.random() честно предупреждает: метод синхронизирован, и если много потоков просят числа часто, они начинают ждать друг друга. У ThreadLocalRandom свой генератор на каждый поток, очереди не возникает: ThreadLocalRandom.current().nextInt(1, 7).
  • SecureRandom. Из пакета java.security. Единственный из трех, который годится для паролей, токенов, кодов подтверждения и всего, что защищает. Обычный генератор предсказуем: зная его состояние, можно вычислить следующие числа. SecureRandom берет случайность у операционной системы.
Если совсем коротко: для игр и учебных задач хватает Math.random(), для многопоточного кода берите ThreadLocalRandom, а для безопасности только SecureRandom.

Заключение

Я надеюсь, что к концу этого поста вы ознакомились с методом Math.random() в Java. Продолжайте практиковаться для более глубокого овладения концепцией. А до тех пор продолжайте расти!

Вопросы и ответы

Какие числа возвращает Math.random()?

Дробное число типа double от 0.0 включительно до 1.0 исключительно. Единицу метод не вернет никогда, а ноль теоретически может. Распределение равномерное: все значения диапазона примерно равновероятны.

Как получить случайное целое число в диапазоне?

Умножить длину диапазона на результат метода, привести к int и прибавить нижнюю границу: (int) (((max - min) + 1) * Math.random()) + min. Единица в формуле нужна потому, что приведение к int отбрасывает дробную часть: без нее верхняя граница просто не выпадет.

Почему одно и то же число выпадает два раза подряд?

Это нормально. Каждый вызов независим от предыдущего, поэтому повторы не только возможны, но и обязаны иногда случаться: на кубике два броска подряд дают одинаковое значение примерно в одном случае из шести. Если повторы недопустимы, числа нужно запоминать и проверять самому, например складывать их в Set.

Math.random() выдает по-настоящему случайные числа?

Нет, псевдослучайные: их вычисляет алгоритм, отталкиваясь от внутреннего состояния генератора. Для игр, тестовых данных и учебных задач этого достаточно, а вот для паролей, токенов доступа и любых задач безопасности такой генератор не годится: его последовательность предсказуема, если знать состояние.

Можно ли вызывать Math.random() из нескольких потоков?

Да, метод синхронизирован, и это прямо написано в документации. Но там же есть оговорка: если много потоков просят числа часто, они начинают ждать друг друга, и каждому потоку выгоднее иметь собственный генератор. В таком случае берут ThreadLocalRandom из пакета java.util.concurrent.

Чем Math.random() отличается от класса Random?

По документации Math.random() при первом вызове создает один экземпляр java.util.Random и дальше пользуется только им. То есть это удобная обертка над тем же самым генератором. Разница в возможностях: у Random есть методы под конкретные типы, например nextInt(bound), который сразу дает целое число без умножений и приведений, а также nextBoolean(), nextDouble() и генерация с заданным зерном. Читайте также: