Jak vygenerovat náhodné číslo v Java

⚡ Chytré shrnutí

Náhodná čísla v Java pocházejí ze čtyř souvisejících možností standardní knihovny, třídy Random, Math.random, ThreadLocalRandom a SecureRandom, přičemž každá z nich pokrývá jinou kombinaci rychlosti, bezpečnosti vláken a kryptografické síly pro reálné aplikace.

  • 🎲 Náhodná třída: java.util.Random zpřístupňuje nextInt, nextLong, nextDoublea nextBoolean pro běžné primitivní typy.
  • 🧮 Matematika.náhodná: Math.random vrací hodnotu typu double mezi 0.0 včetně a 1.0 bez nich pomocí sdílené instance Random.
  • 🎯 Vlastní rozsahy: Předejte mez do nextInt nebo škálujte Math.random pro generování hodnot v rámci libovolného minima a maxima.
  • 🧵 Bezpečnost vlákna: ThreadLocalRandom v java.util.concurrent dává každému vláknu vlastní generátor a v případě soupeření překonává sdílený Random.
  • 🔐 Zabezpečení SecureRandom v java.security vytváří kryptograficky silné hodnoty pro hesla, tokeny a klíče relace.
  • ???? Reprodukovatelnost: Nastavením fixní délky pro Random se testy a simulace stanou deterministickými napříč běhy.

Jak vygenerovat náhodné číslo v Java

Náhodná čísla se objevují všude Java, od dat z jednotkových testů a her s hodem kostkami až po žetony relací a zamíchané balíčky. Tento tutoriál vysvětluje, jak generovat náhodná čísla v Java použití všech možností ve standardní knihovně a jak vybrat tu správnou pro daný úkol.

Generovat náhodné číslo v Java

Jedno Java Standardní knihovna nabízí čtyři běžné způsoby generování náhodných čísel:

  • java.util.Random je univerzální třída. Vytváří hodnoty typu boolean, int, long, float a double pomocí metod, jako například nextInt, nextLong, a nextDouble.
  • Math.random je statický pomocník, který vrací hodnotu typu double mezi 0.0 (včetně) a 1.0 (bez ní) pomocí sdílené metody. Random vnitřně.
  • ThreadLocalRandom in java.util.concurrent dává každému vláknu vlastní generátor, takže více vláken nesoupeří v jedné instanci.
  • SecureRandom in java.security vytváří kryptograficky silná pseudonáhodná čísla pro hesla, identifikátory relací a klíče.

Níže uvedené části ukazují, jak pomocí každého přístupu vygenerovat deset náhodných čísel.

Příklad: Generování náhodných čísel pomocí Java Náhodná třída

První příklad používá java.util.Random pro vytvoření deseti celých čísel v rozsahu 0 až 99 včetně:

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);
        }
    }
}

Výstup:

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

Příklad Random je vytvořen jako objGenerator, nextInt(int bound) Metoda vrací hodnotu mezi 0 (včetně) a zadanou hranicí (exkluzivní), takže nextInt(100) vrací hodnoty od 0 do 99. Aby byla sekvence reprodukovatelná, předejte konstruktoru například seed. new Random(42); stejné seed vždy produkuje stejnou sekvenci, což je užitečné v testech a simulacích.

Příklad: Použití Java Matematika.náhodná

Pro vygenerování deseti náhodných hodnot v rozsahu 0.0 až 1.0 zavolejte funkci static Math.random metoda uvnitř smyčkaToto je nejrychlejší způsob, jak získat náhodný double bez vytvoření objektu generátoru:

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

Výstup:

0.46518450373334297
0.14859851177803485
0.5628391820492477
0.6323378498048606
0.1740198445692248
0.9140544122258946
0.9167350036262347
0.49251219841030147
0.7426056725722353
0.2039418871298877

pod kapotou, Math.random vytváří jeden statický Random při prvním použití a hovorech nextDouble na tom. Tento jeden sdílený generátor je pro dema v pořádku, ale při velkém vícevláknovém zatížení se stává úzkým hrdlem, o čemž se budeme zabývat v následujících částech.

Generování náhodného čísla ve vlastním rozsahu

Reálné programy obvykle potřebují náhodnou hodnotu v určitém rozsahu, například celé číslo mezi 1 a 6 pro hod kostkou nebo dvojnásobek mezi 10.0 a 20.0 pro simulaci. Dva vzory pokrývají téměř každý případ.

Náhodné celé číslo mezi minimem a maximem (včetně):

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);
    }
}

Náhodné double mezi minimem a maximem:

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

Oba vzory fungují tak, že vezmou hodnotu z nativního rozsahu generátoru, upraví ji na šířku cílového rozsahu a posunou ji nahoru o minimum. Pokud jste na Java 8 nebo novější, stejný výsledek je k dispozici i v novější verzi ints, longs, a doubles metody streamu na Random, Například rnd.ints(10, 1, 7).forEach(System.out::println) pro deset hodů kostkou.

ThreadLocalRandom pro vícevláknové zpracování Code

Jeden sdílený Random je vláknově bezpečné, ale pomalé v případě soupeření, protože každé vlákno se musí synchronizovat na stejném interním semenu. ThreadLocalRandom, přidáno v Java 7 a žijící v java.util.concurrent, dává každému vláknu vlastní generátor, takže nedochází k žádnému soupeření o zámky.

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);
    }
}

Použijte ThreadLocalRandom.current() uvnitř pracovních vláken, paralelních streamů a jakékoli souběžné úlohy. Všimněte si, že setSeed hodí UnsupportedOperationException, takže seedování pro reprodukovatelnost není podporováno; pokud potřebujete fixní seed, držte se prostého Random.

SecureRandom pro náhodné výběry citlivé na zabezpečení Numbers

Případy Random a ThreadLocalRandom nejsou kryptograficky bezpečné. Na základě několika výstupních vzorků může útočník rekonstruovat vnitřní stav a předpovědět budoucí hodnoty. Pro hesla, tokeny relací, hodnoty salt a kryptografické klíče použijte java.security.SecureRandom Místo toho čerpá semenný materiál z entropického fondu operačního systému a produkuje hodnoty, které odolávají predikci.

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 je pomalejší než Random protože používá silnější algoritmy a bohatší seedmaterial. Vyhraďte si ho pro bezpečnostní práce a rychlejší generátory použijte pro hry, simulace a testovací data.

Nejčastější dotazy

Vytvořte instanci java.util.Random a zavolejte nextInt, nextLong, nextDouble, nebo nextBoolean. Pro rychlý jednořádkový příklad použijte Math.random, který vrací hodnotu typu double mezi 0.0 a 1.0. Oba přístupy jsou součástí standardní knihovny.

Pro celá čísla volejte metodu random.nextInt(max – min + 1) + min, pro čísla typu double volejte metodu min + (max – min) * Math.random(). Vzorce škálují rozsah generátoru podle cílového okna a posunou ho o minimální hodnotu.

Random je plnohodnotná třída s metodami pro mnoho primitivních typů a podporuje očkování. Math.random je statický pomocník, který vrací hodnotu typu double mezi 0.0 a 1.0. Interně Math.random volá jednu sdílenou instanci třídy Random.

Ano, ale souběžná volání soupeří o stejné interní seed, což zpomaluje kód s vysokou vláknovou strukturou. Použijte ThreadLocalRandom.current() z java.util.concurrent, abyste každému vláknu přidělili vlastní generátor a tento soupeřský proces odstranili.

Předejte konstruktoru Random pevnou hodnotu typu long, například new Random(42), nebo zavolejte setSeed(42). Generátor bude při každém spuštění vytvářet stejnou sekvenci, což je nezbytné pro opakovatelné testy a simulace.

Použijte SecureRandom vždy, když hodnota musí odolávat predikci, například u hesel, tokenů relací, hodnot Salt, jednorázových kódů a kryptografických klíčů. Plain Random je rychlý, ale předvídatelný, takže není bezpečný pro bezpečnostní účely.

Rámce strojového učení používají pseudonáhodné generátory k inicializaci vah, promíchávání trénovacích dat a dělení validačních sad. Oprava počáteční hodnoty umožňuje reprodukovatelnost experimentů, takže týmy mohou spolehlivě porovnávat běhy modelů a ladit výsledky.

Ano. GitHub Copilot scaffolduje úryvky Random, ThreadLocalRandom a SecureRandom, porovnává vzorce pro škálování rozsahu a JUnit testy. RevProhlédněte si každý návrh, abyste se ujistili, že vybraná třída odpovídá danému případu použití, zejména u kódu citlivého na bezpečnost.

Shrňte tento příspěvek takto: