Ints: примеры (JAVA)
ints: IntStreamОписание метода Random.ints
Метод ints принадлежит классу java.util.Random и возвращает поток примитивов IntStream, наполняемый псевдослучайными целыми числами. Доступны несколько перегрузок, позволяющих получать как бесконечные, так и конечные потоки, а также задавать диапазон генерируемых значений.
Сигнатуры (основные варианты):
IntStream ints()- бесконечный поток случайныхintв полном диапазонеInteger.MIN_VALUE..Integer.MAX_VALUE.IntStream ints(long streamSize)- конечный поток длиныstreamSize(еслиstreamSize >= 0), значения в полном диапазонеint.IntStream ints(int randomNumberOrigin, int randomNumberBound)- бесконечный поток в диапазоне[randomNumberOrigin, randomNumberBound), то есть правая граница исключается.IntStream ints(long streamSize, int randomNumberOrigin, int randomNumberBound)- конечный поток длиныstreamSizeс числами из диапазона[randomNumberOrigin, randomNumberBound).
Возвращаемый тип: java.util.stream.IntStream. Потоки ленивы; генерация значений происходит только при выполнении терминальной операции.
Особенности и ограничения:
- Если указан
streamSizeменьше нуля, генерируетсяIllegalArgumentException. - Если
randomNumberOrigin >= randomNumberBound, генерируетсяIllegalArgumentException. - Диапазон правая граница - исключается. Для включающего диапазона нужно увеличить правую границу на единицу, учитывая опасность переполнения.
- Метод использует алгоритм генератора псевдослучайных чисел класса
Random. Для многопоточных сред чаще используютThreadLocalRandomилиSplittableRandomдля лучшей производительности и уменьшения конкуренции.
Короткие практические примеры
Создание 5 случайных чисел (бесконечный поток с ограничением).
import java.util.Random;
import java.util.stream.IntStream;
Random r = new Random();
IntStream s = r.ints().limit(5);
s.forEach(System.out::println);
Возможный результат:
-1155484576 -723955400 1033096058 -1690734402 -49796531
Генерация ровно 4 чисел в диапазоне [0, 10):
Random r = new Random();
int[] a = r.ints(4, 0, 10).toArray();
System.out.println(java.util.Arrays.toString(a));
Возможный результат:
[3, 0, 7, 9]
Генерация 6 чисел во всём диапазоне int:
Random r = new Random();
int[] a = r.ints(6).toArray();
System.out.println(java.util.Arrays.toString(a));
Возможный результат:
[-1472260557, 68467952, -1953477462, 1298491028, -47061400, 2113341997]
Попытка неверного диапазона приведёт к исключению:
new Random().ints(3, 10, 5).findFirst(); // randomNumberOrigin >= randomNumberBound
Результат:
Exception in thread "main" java.lang.IllegalArgumentException: bound must be greater than origin
Похожие варианты в Java и их особенности
- ThreadLocalRandom.current().ints(...) - специализирован для многопоточных приложений, обеспечивает меньшую конкуренцию и лучшую производительность при параллельной генерации.
- SplittableRandom.ints(...) - предназначен для параллельных вычислений и деления генератора на независимые части. Часто быстрее и лучше масштабируется в больших потоках.
- SecureRandom (наследует методы
Random) - для криптографически стойкой генерации; медленнее и не рекомендуется для высокопроизводительных нелюбых задач. - IntStream.range(…) - не является генератором случайных чисел, но используется для создания последовательностей и индексов, когда требуется детерминированный диапазон.
Когда выбирать: для простых задач подойдёт Random. Для многопоточных ситуаций предпочтение стоит отдать ThreadLocalRandom или SplittableRandom. Для безопасности - SecureRandom.
Аналоги в других языках и отличия
- Python:
import random # randint(a, b) возвращает включительно print([random.randint(0, 9) for _ in range(4)]) # randrange(0,10) как [0,10) print([random.randrange(0, 10) for _ in range(4)])[3, 0, 7, 9] [2, 8, 1, 0]
Отличия:randintвключает обе границы; генератор не потокобезопасен, но прост в использовании. - JavaScript:
// Math.random() в [0,1) function randInt(min, maxExclusive){ return Math.floor(Math.random() * (maxExclusive - min)) + min; } console.log(randInt(0,10));7
Отличие: нет встроенного метода для целых чисел, нужно масштабировать и округлять; не криптографически стойко. - PHP:
echo random_int(0, 9) . PHP_EOL; // криптографически стойкая echo mt_rand(0, 9) . PHP_EOL; // быстрый псевдослучайный5 3
Отличие: есть отдельные функции для крипто и для высокой скорости. - C#:
var rnd = new System.Random(); Console.WriteLine(rnd.Next(0, 10)); // [0,10)4
Отличие: методNextвозвращает значение с исключающей правой границей, как в Java. - Go:
import "math/rand" fmt.Println(rand.Intn(10)) // 0..92
Отличие: простые утилиты в пакетеmath/rand; криптографически стойкая альтернатива вcrypto/rand. - Kotlin:
import kotlin.random.Random println(Random.nextInt(0, 10)) // [0,10)6
Отличие: Kotlin использует свои расширения на базе разных реализаций, поведение ограничений схож с Java. - SQL:
-- Пример MySQL SELECT FLOOR(RAND() * 10) AS r; -- 0..9r 5
Отличие: SQL-диапазон часто строится через умножение случайного [0,1) и округление; контроль качества распределения и потокобезопасности отличается от языковых генераторов.
Типичные ошибки и примеры
1. Неверный диапазон (origin >= bound).
new java.util.Random().ints(1, 10, 10).findFirst();
Результат:
Exception in thread "main" java.lang.IllegalArgumentException: bound must be greater than origin
2. Отрицательный размер потока.
new java.util.Random().ints(-5).count();
Результат:
Exception in thread "main" java.lang.IllegalArgumentException: streamSize must be non-negative
3. Ожидание включающей правой границы. Частая ошибка - предполагать, что ints(origin, bound) включает bound. Для включающей правой границы нужно указать bound + 1, но важно учитывать переполнение при использовании Integer.MAX_VALUE.
4. Использование бесконечного потока без терминальной операции с ограничением (limit) приведёт к зависанию или бесконечной работе.
5. Проблемы производительности при параллельной генерации с единым экземпляром Random из разных потоков: конкурентный доступ снижает скорость. Для многопоточных сценариев предпочтительны ThreadLocalRandom или SplittableRandom.
Изменения и история
Метод ints введён в Java 8 вместе с потоками Stream API. С тех пор поведение и сигнатуры остались стабильными. Дополнительные улучшения касаются производительности и альтернативных реализаций генераторов (например, SplittableRandom и ThreadLocalRandom), но сам контракт Random.ints не претерпел ломающих изменений.
Для криптографии и специальных задач рекомендованы альтернативные классы; в стандартной библиотеке не появлялось новых перегрузок метода ints после Java 8.
Расширенные и нестандартные применения
1) Заполнение массива примитивными значениями случайного размера и преобразование в список:
import java.util.Random;
import java.util.stream.IntStream;
Random r = new Random();
int[] arr = r.ints(10, 0, 100).toArray(); // 10 чисел 0..99
System.out.println(java.util.Arrays.toString(arr));
// Если нужен List:
java.util.List list = IntStream.of(arr).boxed().collect(java.util.stream.Collectors.toList());
System.out.println(list);
[12, 89, 3, 45, 67, 0, 21, 34, 56, 78] [12, 89, 3, 45, 67, 0, 21, 34, 56, 78]
2) Быстрая генерация уникальных случайных чисел в диапазоне с помощью перемешивания:
// Получение k уникальных чисел в 0..n-1
int n = 1000, k = 10;
int[] perm = java.util.stream.IntStream.range(0, n).toArray();
java.util.Random r2 = new java.util.Random();
for (int i = 0; i < k; i++) {
int j = i + r2.nextInt(n - i);
int tmp = perm[i]; perm[i] = perm[j]; perm[j] = tmp;
}
int[] result = java.util.Arrays.copyOfRange(perm, 0, k);
System.out.println(java.util.Arrays.toString(result));
[473, 2, 987, 10, 55, 601, 18, 320, 91, 777]
3) Использование SecureRandom.ints для криптографически стойких значений:
import java.security.SecureRandom;
SecureRandom sr = new SecureRandom();
int[] key = sr.ints(16, 0, 256).toArray(); // байтоподобные значения 0..255
System.out.println(java.util.Arrays.toString(key));
[12, 255, 33, 0, 98, 7, 199, 120, 44, 220, 88, 3, 154, 201, 10, 45]
4) Параллельная генерация и агрегация частот: осторожно с общим Random, лучше использовать тредлокал или SplittableRandom.
import java.util.concurrent.ThreadLocalRandom;
int[] histogram = ThreadLocalRandom.current()
.ints(1_000_000, 0, 100)
.parallel()
.boxed()
.collect(java.util.stream.Collectors.groupingBy(i -> i, java.util.stream.Collectors.summingInt(e -> 1)))
.entrySet().stream()
.sorted(java.util.Map.Entry.comparingByKey())
.mapToInt(e -> e.getValue())
.toArray();
System.out.println("bins: " + histogram.length);
bins: 100
5) Генерация распределения с нестандартным весом: преобразование равномерного потока в требуемое распределение методом инверсии CDF или через взвешенные выборки.
// Простой пример: генерация 0 или 1 с вероятностью p для 1
double p = 0.3;
int[] res = ThreadLocalRandom.current()
.doubles() // поток double в [0,1)
.mapToInt(d -> d < p ? 1 : 0)
.limit(20)
.toArray();
System.out.println(java.util.Arrays.toString(res));
[0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
6) Заполнение ByteBuffer или генерирование случайных байтов через IntStream (полезно при подготовке тестовых данных):
import java.nio.ByteBuffer;
Random r3 = new Random();
byte[] bytes = r3.ints(16, 0, 256).map(i -> (byte) i).collect(() -> new java.util.ArrayList(), (l, b) -> l.add((byte)b), (l1, l2) -> l1.addAll(l2))
.stream().collect(java.util.stream.Collectors.toList())
.stream().mapToInt(Byte::intValue).toArray();
// Проще: r3.ints(16,0,256).collect(...)
System.out.println(java.util.Arrays.toString(bytes));
[12, -1, 33, 0, 98, 7, -57, 120, 44, -36, 88, 3, -102, -55, 10, 45]
Примечание: в некоторых примерах использованы упрощённые приёмы для демонстрации. Для производительности предпочтительнее избегать частого боксинга и ненужного переключения потоков.