Jak wygenerować liczbę losową w Java

⚡ Inteligentne podsumowanie

Liczby losowe w Java pochodzą z czterech powiązanych ze sobą standardowych opcji bibliotecznych: klasy Random, Math.random, ThreadLocalRandom i SecureRandom, z których każda obejmuje inne połączenie szybkości, bezpieczeństwa wątków i siły kryptograficznej dla rzeczywistych zastosowań.

  • 🎲 Klasa losowa: java.util.Random udostępnia nextInt, nextLong, nextDoublei nextBoolean dla typowych typów pierwotnych.
  • 🧮 Matematyka losowa: Math.random zwraca wartość typu double z zakresu od 0.0 włącznie do 1.0 bez uwzględnienia wartości, korzystając ze współdzielonej instancji klasy Random.
  • 🎯 Zakresy niestandardowe: Przekaż granicę do nextInt lub skalę Math.random w celu wygenerowania wartości mieszczących się w dowolnym minimum i maksimum.
  • 🧵 Bezpieczeństwo gwintów: ThreadLocalRandom w java.util.concurrent przydziela każdemu wątkowi własny generator i w przypadku konfliktu działa lepiej niż współdzielony Random.
  • 🔐 Bezpieczeństwo: SecureRandom w java.security generuje kryptograficznie silne wartości dla haseł, tokenów i kluczy sesji.
  • 🌱 Powtarzalność: Zaszczepienie losowego zbioru stałą wartością długą sprawia, że ​​testy i symulacje są deterministyczne w różnych przebiegach.

Jak wygenerować liczbę losową w Java

Losowe liczby pojawiają się wszędzie Java, od danych testów jednostkowych i gier z rzutami kośćmi, po żetony sesji i tasowane talie. Ten samouczek wyjaśnia, jak generować liczby losowe w Java jak korzystać z każdej opcji dostępnej w bibliotece standardowej i jak wybrać tę właściwą do danego zadania.

Wygeneruj liczbę losową w Java

Java Biblioteka standardowa oferuje cztery popularne sposoby generowania liczb losowych:

  • java.util.Random to klasa ogólnego przeznaczenia. Generuje wartości typu boolean, int, long, float i double za pomocą metod takich jak nextInt, nextLong, nextDouble.
  • Math.random jest statycznym pomocnikiem, który zwraca wartość typu double między 0.0 (włącznie) a 1.0 (wyłącznie) przy użyciu współdzielonego Random wewnętrznie.
  • ThreadLocalRandom in java.util.concurrent nadaje każdemu wątkowi własny generator, dzięki czemu wiele wątków nie rywalizuje ze sobą na jednym wystąpieniu.
  • SecureRandom in java.security generuje kryptograficznie silne pseudolosowe liczby dla haseł, identyfikatorów sesji i kluczy.

Poniższe sekcje pokazują, jak wygenerować dziesięć liczb losowych przy użyciu każdej metody.

Przykład: Generowanie liczb losowych za pomocą Java Losowa klasa

W pierwszym przykładzie użyto java.util.Random aby wygenerować dziesięć liczb całkowitych z zakresu od 0 do 99 włącznie:

import java.util.Random;

public class RandomNumbers {
    public static void main(String[] args) {
        Random objGenerator = new Random();
        for (int iCount = 0; iCount < 10; iCount++) {
            int randomNumber = objGenerator.nextInt(100);
            System.out.println("Random No : " + randomNumber);
        }
    }
}

Wyjście:

Random No : 17
Random No : 57
Random No : 73
Random No : 48
Random No : 68
Random No : 86
Random No : 34
Random No : 97
Random No : 73
Random No : 18

Przypadek Random jest stworzony jako objGenerator, nextInt(int bound) metoda zwraca wartość pomiędzy 0 (włącznie) a podaną granicą (bez ograniczeń), więc nextInt(100) zwraca wartości od 0 do 99. Aby sekwencja była powtarzalna, należy przekazać konstruktorowi ziarno, na przykład new Random(42); to samo ziarno zawsze daje tę samą sekwencję, co jest przydatne w testach i symulacjach.

Przykład: użycie Java Matematyka losowa

Aby wygenerować dziesięć losowych wartości z zakresu od 0.0 do 1.0, wywołaj metodę statyczną Math.random metoda wewnątrz pętla. To najszybszy sposób na uzyskanie losowego double'a bez tworzenia obiektu generatora:

public class DemoRandom {
    public static void main(String[] args) {
        for (int xCount = 0; xCount < 10; xCount++) {
            System.out.println(Math.random());
        }
    }
}

Wyjście:

0.46518450373334297
0.14859851177803485
0.5628391820492477
0.6323378498048606
0.1740198445692248
0.9140544122258946
0.9167350036262347
0.49251219841030147
0.7426056725722353
0.2039418871298877

Pod maską, Math.random tworzy pojedynczą statyczną Random przy pierwszym użyciu i połączeniach nextDouble Na tym. Ten pojedynczy, współdzielony generator sprawdza się w wersjach demonstracyjnych, ale staje się wąskim gardłem przy dużym obciążeniu wielowątkowym, o czym mowa w kolejnych sekcjach.

Wygeneruj liczbę losową w niestandardowym zakresie

Rzeczywiste programy zazwyczaj wymagają losowej wartości z określonego zakresu, na przykład liczby całkowitej od 1 do 6 w przypadku rzutu kostką lub liczby podwójnej od 10.0 do 20.0 w przypadku symulacji. Dwa wzorce pokrywają niemal każdy przypadek.

Losowa liczba całkowita pomiędzy min. a maks. (włącznie):

import java.util.Random;

public class RangeDemo {
    public static void main(String[] args) {
        Random rnd = new Random();
        int min = 1;
        int max = 6;
        // nextInt(max - min + 1) returns 0..(max-min), then shift by min
        int dice = rnd.nextInt(max - min + 1) + min;
        System.out.println("Dice roll : " + dice);
    }
}

Losowy dublet pomiędzy min i max:

double min = 10.0;
double max = 20.0;
double value = min + (max - min) * Math.random();
System.out.println("Value : " + value);

Oba wzorce działają poprzez pobranie wartości z natywnego zakresu generatora, skalowanie jej do szerokości zakresu docelowego i przesunięcie w górę o minimum. Jeśli jesteś na Java 8 lub nowszy, ten sam wynik jest dostępny w nowszej wersji ints, longs, doubles metody strumieniowe na Random, Na przykład rnd.ints(10, 1, 7).forEach(System.out::println) na dziesięć rzutów kostką.

ThreadLocalRandom dla wielowątkowości Code

Pojedynczy wspólny Random jest bezpieczny dla wątków, ale powolny w warunkach rywalizacji, ponieważ każdy wątek musi synchronizować się na tym samym wewnętrznym ziarnie. ThreadLocalRandom, dodane Java 7 i mieszka w java.util.concurrent, daje każdemu wątkowi własny generator, dzięki czemu nie występuje rywalizacja o blokadę.

import java.util.concurrent.ThreadLocalRandom;

public class ThreadLocalDemo {
    public static void main(String[] args) {
        // random int in [1, 100]
        int i = ThreadLocalRandom.current().nextInt(1, 101);

        // random long in [1000, 5000]
        long l = ThreadLocalRandom.current().nextLong(1000L, 5001L);

        // random double in [0.0, 1.0)
        double d = ThreadLocalRandom.current().nextDouble();

        System.out.println(i + " " + l + " " + d);
    }
}

Zastosowanie ThreadLocalRandom.current() wewnątrz wątków roboczych, strumieni równoległych i wszelkich zadań współbieżnych. Należy pamiętać, że setSeed rzuca UnsupportedOperationException, więc nie obsługujemy zasiewania w celu zapewnienia powtarzalności; jeśli potrzebujesz stałego zasiewu, trzymaj się zwykłego Random.

SecureRandom do losowych zapytań wymagających bezpieczeństwa Numbers

przypadki Random oraz ThreadLocalRandom Nie są bezpieczne kryptograficznie. Mając kilka próbek wyjściowych, atakujący może zrekonstruować stan wewnętrzny i przewidzieć przyszłe wartości. W przypadku haseł, tokenów sesji, wartości soli i kluczy kryptograficznych należy użyć java.security.SecureRandom Zamiast tego pobiera materiał z puli entropii systemu operacyjnego i generuje wartości, których nie da się przewidzieć.

import java.security.SecureRandom;

public class SecureDemo {
    public static void main(String[] args) {
        SecureRandom secure = new SecureRandom();

        byte[] token = new byte[16];
        secure.nextBytes(token);          // 128-bit random token

        int otp = secure.nextInt(1_000_000); // 6-digit one-time code

        System.out.println("OTP : " + String.format("%06d", otp));
    }
}

SecureRandom jest wolniejszy niż Random Ponieważ wykorzystuje silniejsze algorytmy i bogatszy materiał źródłowy. Zarezerwuj go do prac związanych z bezpieczeństwem, a szybsze generatory wykorzystaj do gier, symulacji i danych testowych.

FAQ

Utwórz instancję java.util.Random i wywołaj nextInt, nextLong, nextDoublelub nextBoolean. Aby szybko napisać jednolinijkową formułę, użyj funkcji Math.random, która zwraca wartość typu double z zakresu od 0.0 do 1.0. Oba podejścia są zawarte w bibliotece standardowej.

Wywołaj random.nextInt(max – min + 1) + min dla liczb całkowitych lub min + (max – min) * Math.random() dla liczb zmiennoprzecinkowych. Formuły skalują zakres generatora do okna docelowego i przesuwają go o minimalną wartość.

Random to pełna klasa z metodami dla wielu typów prymitywnych i obsługą seedingu. Math.random to statyczna klasa pomocnicza, która zwraca wartość typu double z zakresu od 0.0 do 1.0. Wewnętrznie Math.random wywołuje pojedynczą, współdzieloną instancję klasy Random.

Tak, ale współbieżne wywołania kolidują z tym samym wewnętrznym ziarnem, co spowalnia kod o dużej liczbie wątków. Użyj ThreadLocalRandom.current() z java.util.concurrent, aby nadać każdemu wątkowi własny generator i wyeliminować tę kolizję.

Przekaż stałą wartość typu long do konstruktora Random, na przykład new Random(42), lub wywołaj setSeed(42). Generator będzie generował tę samą sekwencję przy każdym uruchomieniu, co jest niezbędne do powtarzalnych testów i symulacji.

Używaj SecureRandom zawsze, gdy wartość musi być odporna na przewidywanie, na przykład hasła, tokeny sesji, wartości salt, kody jednorazowe i klucze kryptograficzne. Tryb Plain Random jest szybki, ale przewidywalny, dlatego nie jest bezpieczny dla bezpieczeństwa.

Platformy uczenia maszynowego wykorzystują generatory pseudolosowe do inicjalizacji wag, tasowania danych treningowych i dzielenia zestawów walidacyjnych. Ustalenie ziarna sprawia, że ​​eksperymenty są powtarzalne, co pozwala zespołom porównywać przebiegi modeli i niezawodnie debugować wyniki.

Tak. GitHub Copilot tworzy szkielety fragmentów kodu Random, ThreadLocalRandom i SecureRandom, dopasowując formuły skalowania zakresu i JUnit testów. RevPrzejrzyj każdą sugestię, aby upewnić się, czy wybrana klasa pasuje do danego przypadku użycia, zwłaszcza w przypadku kodu wrażliwego na bezpieczeństwo.

Podsumuj ten post następująco: