
6日でできる 新Java入門|ランダム数
ランダム数を使いこなして、Javaプログラムに「毎回ちがう面白さ」を生み出そう
Javaのプログラムを作っていると、毎回まったく同じ結果だけでは物足りない場面がよくあります。
たとえばクイズアプリなら、出題順がいつも同じだと、すぐに答えを覚えられてしまいます。ゲームでも、敵の動きやアイテムの出現が完全に固定されていると、遊びの幅がぐっと狭くなってしまいます。
そんなときに活躍するのがランダム数です。
ランダム数とは、次にどんな値が出るかを人が簡単には予測できない数値のことです。Javaでは、このランダム数を使うことで、クイズの出題順を変えたり、選択肢の並びを入れ替えたり、ゲームに偶然性を加えたりできます。つまり、プログラムに「ゆらぎ」や「変化」を与えるための大切な仕組みだと考えると分かりやすいです。
今回の記事では、Javaでランダム数を扱う代表的な方法として Randomクラス を中心に見ていきます。あわせて、実際の活用例として lesson23_1.java を使い、prefectures.txt に入っている都道府県と県庁所在地のデータをもとに、ランダム出題のクイズを作る流れを丁寧に確認していきます。
ランダム数とは何か
ランダム数は、プログラムの動きを単調にしないための重要な要素です。
「毎回同じ入力なら毎回同じ結果になる」というのはプログラムの基本ですが、そこにランダム数を組み込むと、同じプログラムでも実行するたびに少しずつ違う結果を出せるようになります。
たとえば、次のような用途でよく使われます。
| 利用場面 | ランダム数の役割 |
|---|---|
| クイズアプリ | 問題をランダムに出題する |
| 選択式問題 | 選択肢の並び順をランダムにする |
| ゲーム | 敵の出現位置やアイテム入手をランダムにする |
| シミュレーション | 偶然性のある動きを再現する |
今回のテーマである県庁所在地当てクイズでは、次の2つの部分にランダム数が活躍します。
| ランダム化する対象 | 目的 |
|---|---|
| どの都道府県を出題するか | 毎回違う問題を出せるようにする |
| 正解やダミー選択肢の並び | 答えの位置を固定しないようにする |
このように、ランダム数はただ数をバラバラに出すためのものではなく、ユーザー体験をより自然で楽しいものにするための仕組みでもあります。
Javaでランダム数を扱う代表的な方法
Javaでは、ランダム数を扱う方法として主に次の2つがよく使われます。
| 方法 | 特徴 |
|---|---|
| Randomクラス | いろいろな型のランダム値を生成できる |
| Math.random() | 0.0以上1.0未満の double 値を手軽に得られる |
実務でも学習でも、まずしっかり覚えておきたいのは Randomクラス です。
理由は、整数・真偽値・実数など、いろいろな種類のランダム値をまとめて扱えるからです。
Randomクラスの基本
Randomクラスは、ランダムな値を生成するための専用クラスです。
使うには、まず import 文で読み込み、次にオブジェクトを作成します。
import java.util.Random;
Random rand = new Random();この rand を通して、さまざまなランダム値を取り出せます。
Randomクラスの主なメソッド
よく使うメソッドを表にまとめると、次のようになります。
| メソッド | 戻り値の型 | 内容 |
|---|---|---|
| nextBoolean() | boolean | true または false をランダムに返す |
| nextInt() | int | int の範囲でランダムな整数を返す |
| nextInt(int n) | int | 0以上 n未満の整数を返す |
| nextLong() | long | long の範囲でランダムな整数を返す |
| nextDouble() | double | 0.0以上1.0未満の実数を返す |
| nextFloat() | float | 0.0以上1.0未満の実数を返す |
この中でも特によく使うのが nextInt(int n) です。
たとえば、
int n = rand.nextInt(10);と書くと、0~9 のどれかが返されます。
ここで大事なのは、10 そのものは含まれないことです。
| 書き方 | 取り出される範囲 |
|---|---|
| rand.nextInt(10) | 0~9 |
| rand.nextInt(4) | 0~3 |
| rand.nextInt(choices.size()) | 0~choices.size() - 1 |
この「0以上、指定した数未満」というルールは、配列や ArrayList の添字ととても相性がいいです。
そのため、リストの中からランダムに1つ選ぶ処理では定番の書き方になります。
lesson23_2.java で見るランダム出題クイズ
ここからは、この記事の中心となるサンプルを見ていきましょう。
このプログラムでは、prefectures.txt に入っている 都道府県名,県庁所在地 のデータを読み込み、その中からランダムに3問出題します。
さらに、正解だけでなくダミーの選択肢もランダムに作られるので、毎回違うクイズになります。
ファイルの配置
今回使うテキストファイルは prefectures.txt です。
Eclipse で実行する場合は、プロジェクト直下に置きます。
プログラム全体
ファイル名:lesson23_1.java
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Random;
public class lesson23_2 {
public static void main(String[] args) throws Exception {
// データの読み込み
BufferedReader br = new BufferedReader(new FileReader("prefectures.txt"));
ArrayList<String> prefectures = new ArrayList<String>();
ArrayList<String> capitals = new ArrayList<String>();
String line;
while ((line = br.readLine()) != null) {
int pos = line.indexOf(',');
prefectures.add(line.substring(0, pos));
capitals.add(line.substring(pos + 1));
}
br.close();
Random rand = new Random();
// 3問だけ出題
for (int i = 1; i <= 3; i++) {
int qIndex = rand.nextInt(prefectures.size());
String question = prefectures.remove(qIndex);
String correct = capitals.remove(qIndex);
// ダミー選択肢を作成
ArrayList<String> choices = new ArrayList<String>();
for (int j = 0; j < 3; j++) {
int cIndex = rand.nextInt(prefectures.size());
choices.add(capitals.remove(cIndex));
prefectures.remove(cIndex);
}
// 正解をランダムな位置に挿入
int insertPos = rand.nextInt(choices.size() + 1);
choices.add(insertPos, correct);
// 問題と選択肢を表示
System.out.println("Q" + i + ": 「" + question + "」の県庁所在地は?");
for (int k = 0; k < choices.size(); k++) {
System.out.println((k + 1) + ": " + choices.get(k));
}
System.out.println("(正解は" + (insertPos + 1) + ")");
}
}
}ファイル名:prefectures.txt
北海道,札幌
青森県,青森
岩手県,盛岡
宮城県,仙台
秋田県,秋田
山形県,山形
福島県,福島
茨城県,水戸
栃木県,宇都宮
群馬県,前橋
埼玉県,さいたま
千葉県,千葉
東京都,東京
神奈川県,横浜
新潟県,新潟
富山県,富山
石川県,金沢
福井県,福井
山梨県,甲府
長野県,長野
岐阜県,岐阜
静岡県,静岡
愛知県,名古屋
三重県,津
滋賀県,大津
京都府,京都
大阪府,大阪
兵庫県,神戸
奈良県,奈良
和歌山県,和歌山
鳥取県,鳥取
島根県,松江
岡山県,岡山
広島県,広島
山口県,山口
徳島県,徳島
香川県,高松
愛媛県,松山
高知県,高知
福岡県,福岡
佐賀県,佐賀
長崎県,長崎
熊本県,熊本
大分県,大分
宮崎県,宮崎
鹿児島県,鹿児島
沖縄県,那覇実行結果の一例は次のようになります。
Q1: 「埼玉県」の県庁所在地は?
1: さいたま
2: 福井
3: 岡山
4: 福岡
(正解は1)
Q2: 「三重県」の県庁所在地は?
1: 千葉
2: 山口
3: 津
4: 奈良
(正解は3)
Q3: 「福島県」の県庁所在地は?
1: 松山
2: 福島
3: 札幌
4: 新潟
(正解は2)ただし、ランダム数を使っているので、実行のたびに問題も選択肢も変わります。
lesson23_1.java の流れをやさしく読み解く
このプログラムは、処理の流れをつかむととても理解しやすくなります。
大きく分けると、次の4段階で動いています。
| 段階 | 内容 |
|---|---|
| 1 | prefectures.txt を1行ずつ読み込む |
| 2 | 都道府県名と県庁所在地を別々の ArrayList に入れる |
| 3 | ランダムに問題を1つ選ぶ |
| 4 | ランダムにダミー選択肢を作り、正解もランダム位置に入れる |
ファイルからデータを読み込む処理
まず、BufferedReader と FileReader を使って prefectures.txt を読み込んでいます。
BufferedReader br = new BufferedReader(new FileReader("prefectures.txt"));そのあと、1行ずつ読んで、カンマの位置を探します。
int pos = line.indexOf(',');たとえば、1行が
北海道,札幌だった場合、カンマより前は 北海道、後ろは 札幌 です。
そこで substring を使って分割しています。
prefectures.add(line.substring(0, pos));
capitals.add(line.substring(pos + 1));この結果、2つの ArrayList が次のように対応して作られます。
| prefectures | capitals |
|---|---|
| 北海道 | 札幌 |
| 青森県 | 青森 |
| 岩手県 | 盛岡 |
| ... | ... |
ここで重要なのは、同じ添字に対応関係があることです。
つまり、prefectures.get(0) が 北海道 なら、capitals.get(0) は 札幌 です。
この「同じ番号どうしが1セット」という考え方が、後のランダム出題で効いてきます。
問題をランダムに選ぶしくみ
問題文を作るときは、まず都道府県一覧の中から1つをランダムに選びます。
int qIndex = rand.nextInt(prefectures.size());ここでは、prefectures.size() が上限になっています。
たとえばデータが47件あれば、0~46 のどれかが返されます。
その添字を使って、問題にする都道府県と正解の県庁所在地を取り出します。
String question = prefectures.remove(qIndex);
String correct = capitals.remove(qIndex);ここで remove を使っているのが大きなポイントです。
get ではなく remove にすることで、取り出したデータはリストから消えます。
つまり、同じ都道府県が次の問題で再登場しなくなります。
この仕組みによって、すでに出題した問題をもう一度出してしまうことを防いでいるわけです。
ダミー選択肢もランダムに作る
次に、正解ではない選択肢を3つ作っています。
ArrayList<String> choices = new ArrayList<String>();
for (int j = 0; j < 3; j++) {
int cIndex = rand.nextInt(prefectures.size());
choices.add(capitals.remove(cIndex));
prefectures.remove(cIndex);
}ここでもランダムな添字を使って、残っているデータの中から県庁所在地を取り出しています。
しかも、ここでも remove を使っているので、一度使ったダミー選択肢は再利用されません。
この処理には、次のような意味があります。
| 処理 | 意味 |
|---|---|
| rand.nextInt(prefectures.size()) | 残っている候補からランダムに1件選ぶ |
| capitals.remove(cIndex) | ダミー候補として県庁所在地を取り出す |
| prefectures.remove(cIndex) | 対応する都道府県も同時に削除する |
なぜ都道府県側も削除するのかというと、2つの ArrayList の対応関係を壊さないためです。
片方だけ削除すると、添字がずれてしまって、都道府県と県庁所在地の組み合わせが崩れてしまいます。
ここはとても大事な点です。
2つの ArrayList を並行して使うときは、同じ位置の要素がペアになっているので、削除も必ず同じ添字で両方に対して行う必要があります。
正解の位置をランダムにする
ダミー選択肢を3つ入れただけでは、まだ正解は入っていません。
そこで、正解を 1~4 のどこかにランダムで差し込みます。
int insertPos = rand.nextInt(choices.size() + 1);
choices.add(insertPos, correct);この時点で choices.size() は 3 なので、
rand.nextInt(4)と同じ意味になります。
つまり、0~3 のどこかに正解が挿入されます。
この処理があるおかげで、正解が毎回同じ位置に来ることがありません。
もし正解がいつも4番目に入る仕様だったら、プログラムとしては動いていても、クイズとしての面白さはかなり下がってしまいます。
remove を使う意味を整理しておこう
このプログラムでは remove がとても重要な役割を持っています。
単に要素を取り出すためだけでなく、重複の防止にも使われています。
| remove を使う場面 | 防いでいること |
|---|---|
| 問題を取り出すとき | 同じ問題が再出題されること |
| ダミー選択肢を取り出すとき | 同じ選択肢が重複すること |
| 対応する都道府県も削除するとき | 添字の対応関係が崩れること |
もし remove ではなく get を使っていたら、同じ都道府県が何度も出たり、同じ県庁所在地が複数の選択肢に出たりする可能性があります。
クイズとしての自然さを保つために、使用済みデータをきちんと除外しているわけです。
Randomクラスと Math.random() の違い
Javaでは Randomクラス 以外に Math.random() も使えます。
どちらもランダム値を扱えますが、使い勝手には違いがあります。
| 方法 | 特徴 |
|---|---|
| Math.random() | 0.0以上1.0未満の double 値を返す |
| Random の nextInt(int n) | 範囲を指定して整数を取り出せる |
| Random の nextBoolean() など | 整数以外の型にも対応できる |
たとえば Math.random() を使って 0~9 の整数を作るなら、こんな書き方になります。
int n = (int)(Math.random() * 10);これでもできますが、整数の範囲指定をしたいときは
int n = rand.nextInt(10);のほうが読みやすく、ミスもしにくいです。
そのため、今回のように「リストの中からランダムに1つ選ぶ」という場面では、Randomクラスのほうがとても使いやすいです。
Randomクラスの主要APIを整理
最後に、よく使うメソッドを学習用に整理しておきます。
| メソッド | 説明 |
|---|---|
| nextInt() | int 範囲のランダムな整数を返す |
| nextInt(int n) | 0~n-1 の範囲で整数を返す |
| nextBoolean() | true または false を返す |
| nextDouble() | 0.0以上1.0未満の実数を返す |
| nextFloat() | 0.0以上1.0未満の実数を返す |
この中で最優先で覚えたいのは nextInt(int n) です。
ArrayList や配列と組み合わせるときに、本当に出番が多いからです。
このプログラムから見えてくる実践ポイント
lesson23_1.java は、単にランダム数を出して終わるサンプルではありません。
実際のアプリづくりにつながる考え方がたくさん詰まっています。
1つ目は、ランダム数はリスト操作と相性がいいこと
リストのサイズを使って nextInt(prefectures.size()) と書けば、今あるデータの中から安全に1件選べます。
これはクイズだけでなく、抽選・カード配布・おすすめ表示などにも応用できます。
2つ目は、使い終わったデータを除外すると自然な動きになること
一度使った問題や選択肢を remove で消していくことで、重複を防げます。
ランダムに見えるだけでなく、ユーザーにとって違和感のない動きになります。
3つ目は、ランダムにする場所を複数用意すると面白さが増すこと
このプログラムでは、
- 問題そのもの
- ダミー選択肢
- 正解の位置
の3か所でランダム性を使っています。
1か所だけではなく、複数の場所にランダム性を入れることで、毎回の変化がより大きくなります。
これが「同じプログラムなのに飽きにくい」理由です。
図:prefectures.txt から ArrayList に格納する流れ
↓クリックすると拡大表示されます。

この図が示していること
prefectures.txt の1行データが、カンマを境に都道府県名と県庁所在地に分割され、2つの ArrayList に格納される流れを示しています。
この図から分かること
2つの ArrayList はバラバラではなく、同じ添字が対応関係を持っていることが視覚的に分かります。後のランダム出題で、同じ添字を使って問題と正解をセットで扱う理由も理解しやすくなります。
図:ランダム出題と remove の流れ
↓クリックすると拡大表示されます。

この図が示していること
Randomクラスを使って問題を選び、ダミー選択肢もランダムに作り、最後に正解をランダムな位置へ入れる流れを示しています。
この図から分かること
ランダム数は問題選択だけでなく、選択肢の生成や正解の位置調整にも使えることが分かります。また、remove によって使用済みデータを消すことで、重複出題を防いでいることも理解しやすくなります。
おさえておきたいポイント
Randomクラスは、Javaでランダムな動きを作るときの基本です。
特に nextInt(int n) は、ArrayList の size と組み合わせることで、リストの中からランダムな要素を取り出す定番の書き方になります。
そして lesson23_1.java では、単に乱数を出すだけではなく、
- ファイルからデータを読み込む
- リストに整理する
- ランダムに問題を選ぶ
- ランダムに選択肢を作る
- remove で重複を防ぐ
という流れがきれいにつながっています。
この考え方を身につけると、クイズアプリだけでなく、抽選プログラム、カードゲーム風の処理、ランダム表示機能などにも応用しやすくなります。
ランダム数は小さな機能に見えて、プログラムの面白さや使いやすさを大きく変えてくれる大事な技術です。
