Javaの乱数とは?使い方や重複なしでランダムに生成する方法も紹介

「乱数を扱うためにはどうすれば良い?」
「重複しないように乱数を出力する方法はある?」
「乱数を使ったゲームの作成例を見てみたい」

乱数は、次にどのような値が出るのか予測できないランダムな値のことを指します。例えば、サイコロを振ると1から6までのいずれかの数字が出ますが、どの数字が出るかは振るまでわかりません。

Javaの乱数は、パスワードの暗号化やセキュリティ関連の処理で使われたり、ゲームのランダムなイベントの生成に使われたりします。

乱数の使用は、アプリケーションに予測不可能な要素を加えることができる重要な概念のひとつです。

この記事ではJavaの乱数に焦点を当て、サンプルコードをもとに基本から応用までを解説します。ぜひ最後までをご覧ください。

Javaの乱数について

乱数とは、予測不可能な値のことです。プログラム中で乱数を生成することによって、さまざまな動的な要素を導入できます。

乱数を使用する機会としては、暗号化処理やシミュレーション、計算問題などのゲーム関連のプログラムを作成する際に頻繁に利用されます。まずは、Javaの乱数について理解を深めていきましょう。

Randomクラスの基礎

Javaの`Random`クラスは、さまざまな種類の乱数を生成するために使用されるクラスです。`Random`クラスを使用するには、まずこのクラスのインスタンスを作成する必要があり、そのインスタンスを使って乱数を生成します。

```java

Random random = new Random();

```

具体的なサンプルコードをみてイメージを深めていきましょう。

```java

import java.util.Random;

public class Test {
    public static void main(String[] args) {
        Random rand = new Random();
        int value = rand.nextInt();
        System.out.println(value);
    }
}

```

この例では、`nextInt`メソッドを使用して整数の乱数を生成しています。`nextInt`メソッドは、`int`型の範囲内で乱数を生成する際に使われるメソッドです。

また、`nextInt(100)`のように引数を指定すると、0から指定した値未満の範囲で乱数を生成します。

`Random`クラスは、この後出てくる`Math`クラスの`random`メソッドよりも柔軟で高速に乱数を生成することができますが、複数のスレッドが一つのプロセス内で実行される「マルチスレッド環境」での使用にはあまり適していません。

マルチスレッド環境で`Random`クラスのインスタンスを共有すると、複数のスレッドが同時に乱数生成器にアクセスすることになり、競合が発生する可能性があるため`ThreadLocalRandom`クラスを使用しましょう。

`ThreadLocalRandom`クラスは、`java.util.concurrent`パッケージに属しており、マルチスレッド環境での乱数生成に適しています。

`ThreadLocalRandom`クラスを使ったサンプルコードは以下の通りです。

```java

import java.util.concurrent.ThreadLocalRandom;

public class ThreadLocalRandomExample {
    public static void main(String[] args) {
        int randomInt = ThreadLocalRandom.current().nextInt(100);
        System.out.println(randomInt);
    }
}

```

`ThreadLocalRandom.current()`は、現在のスレッドの`ThreadLocalRandom`インスタンスを返し、`nextInt(100)`メソッドは、0以上100未満の整数の乱数を生成します。

`ThreadLocalRandom`クラスはマルチスレッド環境での使用に最適化されており、スレッドごとに独立した乱数生成器を持つため、スレッド間の競合が発生しにくいです。

Javaの乱数生成クラスとは

Javaの乱数生成クラスとは、プログラム内でランダムな数値を生成するために使用されるクラスのことで、主に`java.util.Random`クラスを使用して乱数を生成します。

`Random`クラスでは、以下のようなそれぞれの型の乱数を生成するメソッドがあり、目的に合わせて使い分けが必要です。

メソッド nextInt() nextInt(int bound) nextLong() nextDouble() nextFloat() nextBoolean()
説明 int型の範囲内で乱数を生成 0以上bound未満の範囲でint型の乱数を生成 long型の範囲内で乱数を生成 0.0以上1.0未満の範囲でdouble型の乱数を生成 0.0以上1.0未満の範囲でfloat型の乱数を生成 真(true)または偽(false)の乱数を生成

`Random`クラスを使用して乱数を生成する以下のサンプルコードを見ていきましょう。

```java

import java.util.Random;

public class RandomExample {
    public static void main(String[] args) {
        Random random = new Random();

        int randomInt = random.nextInt(100); // 0から99までの乱数を生成
        System.out.println("Random integer: " + randomInt);

        double randomDouble = random.nextDouble(); // 0.0以上1.0未満の乱数を生成
        System.out.println("Random double: " + randomDouble);

        boolean randomBoolean = random.nextBoolean(); // 真または偽の乱数を生成
        System.out.println("Random boolean: " + randomBoolean);
    }
}

```

`Random`クラスのインスタンスを生成した後、`nextInt`、`nextDouble`、`nextBoolean`などのメソッドを呼び出して整数、浮動小数点数、真偽値の乱数がそれぞれコンソールに表示されます。

`Random`クラスを使用することで、さまざまな型の乱数を簡単に生成することができるようになり、柔軟でランダムな挙動を実現可能です。

Javaの乱数の基本的な生成方法

ここからは、次のトピック別でJavaにおける目的別の乱数の生成方法を解説します。Javaにおける様々な乱数の出力方法を学んでいきましょう。

重複なしでJavaの乱数をランダムに生成する方法

Javaで重複なしの乱数をランダムに生成する方法には主に3つの方法があります。まずは、`Set`コレクションを使用して重複を自動的に排除する方法です。

以下のサンプルコードを見てください。

```java

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class UniqueRandomNumbers {
    public static void main(String[] args) {
        Random random = new Random();
        Set uniqueNumbers = new HashSet<>();

        while (uniqueNumbers.size() < 10) {
            int number = random.nextInt(100);
            uniqueNumbers.add(number);
        }

        System.out.println("Unique random numbers: " + uniqueNumbers);
    }
}

```

`Random`クラスのインスタンスを生成して乱数生成器を初期化して、`HashSet`のインスタンスを生成して、重複のない整数を保持するためのセットを作成しています。

`while`ループを使用して、セットのサイズが10未満である間、0から99までの範囲の整数乱数を生成し、セットに追加すれば重複のない乱数を出力可能です。

次に、配列を使用して乱数を格納し、新しい乱数を生成するたびに重複チェックを行う方法を見ていきましょう。

```java

import java.util.Random;

public class UniqueRandomNumbersArray {
    public static void main(String[] args) {
        Random random = new Random();
        int[] uniqueNumbers = new int[10];
        int count = 0;

        while (count < uniqueNumbers.length) {
            int number = random.nextInt(100);
            if (!contains(uniqueNumbers, number)) {
                uniqueNumbers[count++] = number;
            }
        }

        System.out.print("Unique random numbers: ");
        for (int num : uniqueNumbers) {
            System.out.print(num + " ");
        }
    }

    public static boolean contains(int[] array, int number) {
        for (int element : array) {
            if (element == number) {
                return true;
            }
        }
        return false;
    }
}

```

`Random`クラスのインスタンスを生成して乱数を初期化、長さ10の整数配列`uniqueNumbers`を用意して、重複のない乱数を格納して、`while`ループを使用して、配列が埋まるまで乱数を生成し続けます。

`contains`メソッドを使用して、生成された乱数が既に配列に含まれているかどうかを`true`と`false`でチェックして重複がなければ配列に追加し、`count`をインクリメントします。

この方法の利点は、特定の範囲の整数から重複のない乱数を生成することができる点です。大量の乱数を生成する場合や、範囲が広い場合には効率が低下する可能性があるので他の方法を検討しましょう。

最後にあらかじめリストに数値を格納し、`Collections.shuffle`メソッドを使用してランダムに並べ替える方法です。

```java

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ShuffleUniqueNumbers {
    public static void main(String[] args) {
        List numbers = new ArrayList<>();

        for (int i = 0; i < 100; i++) {
            numbers.add(i);
        }

        Collections.shuffle(numbers);

        System.out.println("Unique random numbers: " + numbers.subList(0, 10));
    }
}

```

`ArrayList`を使用して0から99までの整数をリストに格納して、`Collections.shuffle`メソッドを使用してリスト内の要素をランダムに並べ替え、シャッフルされたリストから先頭の10個の要素を取り出し、重複のない乱数として出力しています。

利点は、特定の範囲の整数から重複のない乱数を効率的に生成できることです。リストに数値を格納し、一度シャッフルすれば、その後はリストから順に要素を取り出すだけで重複のない乱数を得られます。

使用する場面や条件に応じて、適切な方法を選択してください。

Mathクラスを用いた乱数の生成方法

`Math`クラスには`random()`という静的メソッドがあり、これを使用することで0.0以上1.0未満の範囲で`double`型の乱数を生成できます。

以下のサンプルコードを見てください。

```java

public class MathRandomExample {
    public static void main(String[] args) {
        double randomValue = Math.random();
        System.out.println("乱数: " + randomValue);
    }
}

```

実行すると、「0.21648518832152353」のような0.0以上1.0未満の実数がランダムに出力されます。

`Math.random()`メソッドは実数を返しますが、整数の乱数を生成したい場合は、少し工夫が必要です。0から9までの整数の乱数を得たい場合は、以下のように記述します。

```java

public class Test {
    public static void main(String[] args) {
        int d = (int)(Math.random() * 10);
        System.out.println(d);
    }
}

```

`Math.random()`で得られた乱数に10を掛けて、0.0以上10.0未満の実数を生成しています。int型にキャストすることで、0から9までの整数の乱数を得られますよ。

シード値の指定方法

シード値とは、乱数生成アルゴリズムの開始点となる値のことを指し、同じシード値を使って乱数を生成すれば、同じ乱数列が得られる特性があります。
Javaでシード値を指定する方法は、主に`Random`クラスを使用して、`Random`クラスのコンストラクタにシード値を渡すことで、シード値を設定することが可能です。

以下のサンプルコードを見てください。

```java

import java.util.Random;

// RandomSampleという名前のクラスを定義
public class RandomSample {
    // mainメソッドを定義
    public static void main(String[] args) {
        // コンストラクタでシード値を指定してRandomオブジェクトを生成
        // シード値123Lを使用してrandom1を初期化
        Random random1 = new Random(123L);

        // デフォルトコンストラクタでRandomオブジェクトを生成
        Random random2 = new Random();
        // setSeedメソッドでシード値を指定
        // シード値123Lを使用してrandom2を初期化
        random2.setSeed(123L);
    }
}

```

`Random`クラスのオブジェクトを2つ生成して、1つ目のオブジェクト`random1`はコンストラクタでシード値を指定して初期化、2つ目のオブジェクト`random2`は、デフォルトコンストラクタで生成した後、`setSeed`メソッドを使用してシード値を指定しています。

同じシード値を使用すれば、同じ乱数列が得られるため、再現性を持たせることが可能です。以下のサンプルコードを見ていきましょう。

```java

import java.util.Random;

public class RandomSample2 {
    public static void main(String[] args) {
        Random random1 = new Random(8);
        Random random2 = new Random(8);
        Random random3 = new Random(10);

        System.out.println("random1: " + random1.nextInt());
        System.out.println("random2: " + random2.nextInt());
        System.out.println("random3: " + random3.nextInt());
    }
}

```

`random1`と`random2`には同じシード値が指定されているため、同じ乱数が生成され、`random3`には異なるシード値が指定されているため、異なる乱数が生成されます。

シード値が予測可能である場合、乱数列も予測可能となるため、セキュリティが重要な用途では、このあと解説する`SecureRandom`クラスを使用するようにしましょう。

SecureRandomクラスによる乱数の生成方法

`SecureRandom`クラスは、標準の`Random`クラスよりも強力な乱数生成機能で、暗号化などのセキュリティ関連の用途に適しています。

以下のサンプルコードを見ていきましょう。

```java

import java.security.SecureRandom;

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

        // 0から99までの乱数を生成
        int randomNumber = secureRandom.nextInt(100);
        System.out.println("乱数: " + randomNumber);
    }
}

```

`SecureRandom`クラスのインスタンスを生成し、`nextInt`メソッドを使用して0から99までの整数の乱数を生成して、0から99までの範囲で生成された乱数がコンソールに出力されます。

`SecureRandom`クラスでも、シード値を指定して乱数生成の振る舞いを制御可能です。シード値は、`setSeed`メソッドを使用して設定します。

```java

secureRandom.setSeed(12345L);

```

`SecureRandom`クラスではシード値の指定は必須ではありません。指定しない場合、システムが提供するエントロピー源(ランダム性の源)を使用して自動的にシード値が設定されます。

Javaの乱数の応用的な使い方

Javaにおける乱数の基礎がわかったら、より応用的な実装方法を見ていきましょう。

乱数を使ったゲームの作成方法

乱数を使って、クイズアプリを作成してみましょう。最初に、乱数生成のための`Random`クラスと、ユーザー入力の受け取りのための`Scanner`クラスをインポートします。

```java

import java.util.Random;
import java.util.Scanner;

```

次に、クイズの質問と回答の準備です。質問文を格納する`questions`配列、各質問に対する回答オプションを格納する`answers`二次元配列、正解の番号を格納する`correctAnswers`配列を用意します。

```java

String[] questions = {
    "次のうち、哺乳類はどれですか?",
    "カンガルーの特徴的な動きは何ですか?",
    "次のうち、鳥類はどれですか?"
};
String[][] answers = {
    {"1.イカ", "2.クジラ", "3.イグアナ"},
    {"1.歩行", "2.ジャンプ", "3.飛行"},
    {"1.サメ", "2.タコ", "3.ペンギン"}
};
int[] correctAnswers = {2, 2, 3};

```

乱数の生成と質問の選択の段階です。`Random`クラスのインスタンスを生成し、`nextInt`メソッドを使って質問のインデックス番号をランダムに選びます。

```java

Random random = new Random();
int questionNumber = random.nextInt(questions.length);

```

その後、questionNumber番目の質問に対する回答オプションがanswers[questionNumber]として取得され、ループ内で、変数answerに格納された各回答オプションをコンソールに出力します。

要するに、ランダムに選ばれた質問と、その質問に対する回答オプションが表示されるように実装します。

```java

System.out.println(questions[questionNumber]);
for (String answer : answers[questionNumber]) {
    System.out.println(answer);
}

```

続いて、`Scanner`クラスのインスタンスを生成し、ユーザーからの回答(整数)を受け取ります。

```java

Scanner scanner = new Scanner(System.in);
int userAnswer = scanner.nextInt();

```

そして、正解かどうかは入力された答えと配列に保存された正解を比較し、ユーザーの回答が正解と一致するかどうかを判定し、結果を表示します。

```java

if (userAnswer == correctAnswers[questionNumber]) {
    System.out.println("正解です!");
} else {
    System.out.println("残念、不正解です。");
}

```

最後に、`Scanner`クラスのインスタンスをクローズしてリソースを解放すれば、完了です。

```java

scanner.close();

```

以下が全ての工程を総括したクイズアプリのサンプルコードです。

```java

import java.util.Random;
import java.util.Scanner;

public class AnimalQuizApp {
    public static void main(String[] args) {
        String[] questions = {
            "次のうち、哺乳類はどれですか?",
            "カンガルーの特徴的な動きは何ですか?",
            "次のうち、鳥類はどれですか?"
        };
        String[][] answers = {
            {"1.イカ", "2.クジラ", "3.イグアナ"},
            {"1.歩行", "2.ジャンプ", "3.飛行"},
            {"1.サメ", "2.タコ", "3.ペンギン"}
        };
        int[] correctAnswers = {2, 2, 3};

        Random random = new Random();
        int questionNumber = random.nextInt(questions.length);

        System.out.println(questions[questionNumber]);
        for (String answer : answers[questionNumber]) {
            System.out.println(answer);
        }

        Scanner scanner = new Scanner(System.in);
        int userAnswer = scanner.nextInt();

        if (userAnswer == correctAnswers[questionNumber]) {
            System.out.println("正解です!");
        } else {
            System.out.println("残念、不正解です。");
        }

        scanner.close();
    }
}

```

基本的な構造を理解すれば、さまざまなバリエーションのクイズアプリを作成することが可能です。

実践的な乱数生成のサンプルコード

ここでは乱数を使ったJavaの実践的なコードを見ていきましょう。

以下は、乱数を使って、色が変化するシンプルなアニメーションを作成しています。

```java

import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.Color;
import java.util.Random;

public class ColorAnimation extends JFrame {
    private static final int WIDTH = 400;
    private static final int HEIGHT = 400;
    private Random random = new Random();

    public ColorAnimation() {
        setSize(WIDTH, HEIGHT);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        while (true) {
            Color color = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
            g.setColor(color);
            g.fillRect(0, 0, WIDTH, HEIGHT);

            try {
                Thread.sleep(500); // 0.5秒ごとに色を変える
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ColorAnimation frame = new ColorAnimation();
        frame.setVisible(true);
    }
}

```

`JFrame`を継承した`ColorAnimation`クラスを作成し、`paint`メソッドをオーバーライドしてウィンドウ全体の色をランダムに変化させ、`Thread.sleep`メソッドを使って一定間隔で色が変わるようにしています。

以下は、英字(大文字・小文字)、数字、特殊文字を含む文字列`CHARACTERS`からランダムに文字を選び、指定された長さ(この例では12文字)のパスワードを生成するコードです。

```java

import java.security.SecureRandom;

public class SecurePasswordGenerator {
    private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+";
    private static final int PASSWORD_LENGTH = 12;

    public static void main(String[] args) {
        SecureRandom random = new SecureRandom();
        StringBuilder password = new StringBuilder();

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

        System.out.println("Generated secure password: " + password.toString());
    }
}

```

`SecureRandom`クラスを使用することで、暗号化に適したセキュリティ乱数を生成して実行するたびに異なるパスワードが生成されます。

`SecureRandom`を使用してパスワードを生成することは、Webアプリケーションやシステム開発においてよく行われる実践的な処理の1つです。

Javaの乱数生成における注意点

Javaでは、乱数を生成するために`Random`クラスと`SecureRandom`クラスの2つが提供されています。

一般的な用途では`Random`クラスで十分ですが、セキュリティが重要な場面では`SecureRandom`クラスを使用するようにしましょう。

`Random`クラスで乱数を生成する際、同じシード値を指定すると同じ乱数列が生成されます。テストやデバッグには便利ですが、予測可能な乱数列はセキュリティ上のリスクがあり、特にシード値が外部から推測される場合、予測しやすくなります。

適切なシード値の選択や、必要に応じて`SecureRandom`クラスの使用を検討しましょう。

`SecureRandom`クラスは暗号化に適した乱数を生成し、よりセキュリティの高いアプリケーションを実現できます。

Javaプログラミングのスキルを活かして収入を増やすなら

なかには、副業での収入獲得やフリーランスへの独立を目的にJavaプログラミングのスキル習得に励んでいる人もいますよね。

ただ、身につけたスキルをどう収入UPに繋げればいいのか、イメージが湧かない人もいるはず。

そんな方は、ぜひフリーランスのミカタをご活用ください。

出典:フリーランスのミカタ

フリーランスのミカタは、平均単価80万円以上の案件を取り揃える、ITエンジニアに特化したフリーランスエージェントです。具体的には、次のような週3回からフルリモートで請け負える案件を豊富に掲載しています。

また希望年収や稼働時間だけでなく、扱うプログラミング言語などを細かく指定して案件を探せるため、自分にあう仕事を見つけやすいサイト仕様になっています。

ただし、上記のような案件は条件として2〜3年の実務経験が求められるケースが多いです。そのため、応募する際はどれくらいの経験が必要なのかを前もってチェックしておきましょう。

フリーランスのミカタを活用すれば、中・長期的な安定収入が得られる案件が見つかりますよ。

どんな案件が掲載されているか気になる人は、下のボタンから自分にあう案件を探してみてください。

まとめ

これまで、基本的な生成方法から応用的な実装、注意点までについて説明しました。

乱数の生成方法は、整数や実数、範囲指定、重複の許可などさまざまで、用途に分けて実装することが大切です。

まだまだ知識が浅く、Javaの他の処理に関しても基礎知識をつけたい!注意点や実践的な使い方を知りたい!という方もいるでしょう。

本記事ではプログラミングに関する多くの疑問を解決できるので、参考にしてみてくださいね。