Losowość w Javie – klasa Random

W programowaniu losowość odgrywa kluczową rolę w wielu dziedzinach, takich jak symulacje, kryptografia, gry komputerowe czy algorytmy heurystyczne. W świecie Javy jednym z najbardziej podstawowych narzędzi do generowania liczb losowych jest klasa Random, znajdująca się w pakiecie java.util. Ten artykuł ma na celu omówienie możliwości klasy Random, jej zastosowań oraz ograniczeń.

Podstawowe informacje o klasie Random

Klasa Random jest częścią biblioteki standardowej Javy i umożliwia generowanie liczb losowych o różnych typach, takich jak liczby całkowite, zmiennoprzecinkowe czy logiczne. W przeciwieństwie do prawdziwej losowości, klasa Random opiera się na deterministycznym algorytmie, co oznacza, że wyniki są pseudolosowe. Każda sekwencja liczb generowana przez Random zależy od początkowego ziarna (seed).

Konstruktorzy klasy Random

Klasa Random oferuje dwa podstawowe sposoby inicjalizacji:

  1. Domyślny konstruktor:
    Random random = new Random();

    W tym przypadku jako ziarno wykorzystywany jest aktualny czas systemowy, co zapewnia różnorodność wyników między kolejnymi uruchomieniami programu.

  2. Konstruktor z parametrem:
    Random random = new Random(12345L);

    Tutaj możemy samodzielnie ustawić wartość ziarna, co sprawia, że sekwencja liczb losowych jest powtarzalna. Jest to przydatne w testach lub symulacjach, gdzie chcemy uzyskać identyczne wyniki.

Generowanie liczb losowych

Klasa Random oferuje wiele metod do generowania różnych typów danych losowych:

Liczby całkowite

  1. Całkowite bez zakresu:
    int randomInt = random.nextInt();

    Zwraca dowolną liczbę całkowitą z zakresu Integer.MIN_VALUE do Integer.MAX_VALUE.

  2. Całkowite w określonym zakresie:
    int randomIntInRange = random.nextInt(100); // Zakres: 0 – 99

    Zwraca liczbę całkowitą z zakresu od 0 (włącznie) do podanej wartości (wyłącznie).

Liczby zmiennoprzecinkowe

  1. Liczby typu float:
    float randomFloat = random.nextFloat();

    Zwraca liczbę zmiennoprzecinkową z zakresu 0.0 (włącznie) do 1.0 (wyłącznie).

  2. Liczby typu double:
    double randomDouble = random.nextDouble();

    Działa podobnie jak nextFloat(), ale zwraca liczby o podwójnej precyzji.

  3. Gaussian:
    double gaussian = random.nextGaussian();

    Generuje liczbę zgodną z rozkładem normalnym (Gaussa) o średniej 0 i odchyleniu standardowym 1.

Liczby logiczne

  1. Losowe wartości logiczne:
    boolean randomBoolean = random.nextBoolean();

    Zwraca losową wartość typu boolean (“true” lub “false”).

Ustawianie ziarna

Ziarno (ang. seed) jest wartością początkową, od której zależy cała sekwencja generowanych liczb. Klasa Random pozwala zmienić ziarno w trakcie działania programu:

random.setSeed(67890L);

Zmiana ziarna powoduje rozpocznięcie nowej sekwencji liczb pseudolosowych.

Przykładowe zastosowania klasy Random

Symulacja rzutu kostką

Random random = new Random();
int diceRoll = random.nextInt(6) + 1; // Zakres: 1 – 6
System.out.println("Wynik rzutu kostką: " + diceRoll);

Generowanie losowego hasła

String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuilder password = new StringBuilder();

for (int i = 0; i < 10; i++) {
    int index = random.nextInt(chars.length());
    password.append(chars.charAt(index));
}

System.out.println("Wygenerowane hasło: " + password);

Symulacja rozkładu normalnego

Random random = new Random();
for (int i = 0; i < 10; i++) {
    double value = random.nextGaussian();
    System.out.println("Liczba z rozkładu normalnego: " + value);
}

Wady i ograniczenia klasy Random

  1. Deterministyczność: Ponieważ klasa Random generuje liczby pseudolosowe, nie nadaje się do zastosowań wymagających prawdziwej losowości, takich jak kryptografia.
  2. Szybkość: W przypadku aplikacji wymagających generowania dużej liczby liczb losowych w krótkim czasie, klasa Random może być niewystarczająco szybka.

Alternatywy dla klasy Random

Klasa SecureRandom

W przypadkach, gdzie wymagana jest większa losowość, np. w kryptografii, można skorzystać z klasy SecureRandom:

import java.security.SecureRandom;
SecureRandom secureRandom = new SecureRandom();
int secureRandomInt = secureRandom.nextInt();

Klasa ThreadLocalRandom

Do zadań wielowątkowych polecana jest klasa ThreadLocalRandom:

import java.util.concurrent.ThreadLocalRandom;
int randomInt = ThreadLocalRandom.current().nextInt(10, 50); // Zakres: 10 – 49

Klasa SplittableRandom

Dla zastosowań wymagających lepszej wydajności i jakości losowości wprowadzono klasę SplittableRandom:

import java.util.SplittableRandom;
SplittableRandom splittableRandom = new SplittableRandom();
int randomInt = splittableRandom.nextInt(1, 100); // Zakres: 1 – 99

Klasa Random pozostaje podstawowym narzędziem do generowania liczb pseudolosowych w Javie, ale jej ograniczenia powodują, że w bardziej zaawansowanych przypadkach warto rozważyć inne klasy, takie jak SecureRandom czy ThreadLocalRandom. Wszystko zależy od wymagań konkretnej aplikacji i oczekiwań dotyczących szybkości oraz jakości losowości.