こんにちは。
今回はJavaのwhile文を使ってみました。while文は繰り返し処理を記述するための構文です。for文とは違った書き方をします。繰り返し処理で、乱数の列を生成するサンプルを作ってみました。乱数の生成にはjava.util.Random#nextIntを使いました。
この記事の前半は、while文の説明です。その次に、RandomクラスのnextInt()メソッドについて使い方を書きました。最後に、while文でそのメソッドを使って、ランダムな数列を作るサンプルプログラムを書きました。
while文の簡単な説明
while文を使うと繰り返し処理を使うことが可能です。while文の簡単な使い方は以下のように条件式を記述する方法です。
ソース
int i = 0;
while(i < 10) { // (1)
System.out.println("iの値:" + i); // (2)
i++; // (3)
}
結果
iの値:0
iの値:1
iの値:2
iの値:3
iの値:4
iの値:5
iの値:6
iの値:7
iの値:8
iの値:9
最初に、変数iを0で初期化します。
(1)では、while文を繰り返すための条件式を括弧内に記述しています。条件式がtrueの場合、波括弧で囲まれた処理が実行されます。上記の場合、(2)と(3)が実行されます。
(2)では変数iの値を出力しています。
(3)では変数iの値を1加算しています。
while文の大まかな処理は以下の通りです。
- 条件式を評価する。
- trueの場合、波括弧で囲まれた処理を実行する。
波括弧内の処理が終わった後、上記の1の処理に戻ります。条件式の結果がfalseの場合、波括弧内の処理が実行されません。
上記サンプルでは、(3)の文があるため、while文の条件式の結果は最初はtrueですが、何回かの繰り返しの後はfalseです。具体的には変数iの値が10になったあと、条件式の結果はfalseです。そこでwhile文は終了です。
上記のwhile文の条件式の個所にtrue自体の記述も可能です。その場合、基本的には繰り返し処理は終わりません。例えば、波括弧内でbreak文を記述すれば、その個所で繰り返し処理を終えることができます。
例えば、以下のようにif文でbreak文を呼び出すという方法が使えます。
ソース
int i = 0;
while(true) {
System.out.println("iの値:" + i);
// (1)
if (i == 5) {
System.out.println("while文を終了します。");
break;
}
i++;
}
System.out.println("全ての処理が終わりました。");
結果
iの値:0
iの値:1
iの値:2
iの値:3
iの値:4
iの値:5
while文を終了します。
全ての処理が終わりました。
上記プログラムの(1)では、if文を使ってbreak文を記述しています。break文が実行されると、while文のループを抜け出すことができます。より正確には、break文を基準に、最も内側のループを抜け出します。
変数iの値が5のとき、if文の条件がtrueになり、break文が実行されます。そのため、println()メソッドで出力される値はi=5の場合で終わりです。
RandomクラスのnextInt()メソッド
今回の記事では乱数を取得するために、RandomクラスのnextInt()メソッドを使って取得できます。
引数の違う次の2つのメソッドが用意されています。
- int nextInt()
- int nextInt(int bound)
今回は2番目のメソッドを使います。このメソッドは、0から引数で指定された値の範囲(0は含むが、引数で指定された値は含まない範囲)でランダムな値を返却します。(API仕様書には「一様分布のint型の擬似乱数値」と記載されています。)
以下は上記のメソッドを引数に100を指定して10回呼び出した結果です。
ソース
Random random = new Random();
int bound = 100;
int value = 0;
for (int i = 0; i < 10; i++) {
value = random.nextInt(bound);
System.out.println((i + 1) + "回目:" + value);
}
注:メインメソッドの内容だけを記載しています。java.util.Randomをインポートしています。
1回目の実行結果
1回目:12
2回目:68
3回目:91
4回目:20
5回目:0
6回目:89
7回目:50
8回目:21
9回目:64
10回目:17
2回目の実行結果
1回目:94
2回目:98
3回目:97
4回目:79
5回目:1
6回目:57
7回目:2
8回目:37
9回目:83
10回目:3
上記プログラムでは、最初にRandomクラスのインスタンスを生成しています。nextInt()メソッドを呼び出すために必要です。(このメソッドがstaticではないため。)
乱数を繰り返し出力するために、for文でnextInt()メソッドを呼び出しています。
繰り返し処理の前にint型変数boundに値100を代入しています。nextInt()メソッドの引数に指定するための変数です。
上記2つの実行結果のように、実行するたびに取得される値が変わります。今回はnextInt()メソッドの引数に値100が指定されるようにしたので、0から99までの値がランダムに取得できました。
上記サンプルは目的が「一定回数の出力」であるため、for文を使いました。
while文で乱数の列を作る
今回は繰り返し回数が一定でない場合の例を考えるため、while文を使います。
以下のような処理のフローを考えます。
- 変数numを初期値0で宣言する。
- 変数numが5でない場合、以下の処理を繰り返す。
- numに0から9までのランダムな値を格納する。
- 以下の形式でコンソールに文字列を出力する。
“回数: ” + [繰り返し回数] + “, 値: ” + num
上記は繰り返しの条件が「変数numが5でない」という条件です。繰り返し回数が固定されてないため、while文を使って、以下のようなサンプルを作成しました。
ソース
import java.util.Random;
public class Test001 {
public static void main(String[] args) {
Random random = new Random();
int num = 0; // 乱数格納用変数
int cnt = 1; // 繰り返し回数
while (num != 5) {
// (1)
num = random.nextInt(10);
// (2)
System.out.println("回数: " + cnt + ", 値: " + num);
// (3)
cnt++;
}
}
}
1回目の実行結果
回数: 1, 値: 9
回数: 2, 値: 8
回数: 3, 値: 2
回数: 4, 値: 4
回数: 5, 値: 9
回数: 6, 値: 3
回数: 7, 値: 1
回数: 8, 値: 3
回数: 9, 値: 9
回数: 10, 値: 7
回数: 11, 値: 5
2回目の実行結果
回数: 1, 値: 7
回数: 2, 値: 8
回数: 3, 値: 8
回数: 4, 値: 9
回数: 5, 値: 1
回数: 6, 値: 3
回数: 7, 値: 1
回数: 8, 値: 9
回数: 9, 値: 4
回数: 10, 値: 9
回数: 11, 値: 9
回数: 12, 値: 8
回数: 13, 値: 8
回数: 14, 値: 3
回数: 15, 値: 7
回数: 16, 値: 4
回数: 17, 値: 3
回数: 18, 値: 9
回数: 19, 値: 6
回数: 20, 値: 4
回数: 21, 値: 3
回数: 22, 値: 5
(1)では、変数numに乱数を格納しています。nextInt()の引数が10なので、10未満の値がこの変数に格納されます。
(2)では、フローの通りの文字列を出力しています。
(3)では、変数cntを1加算しています。これは繰り返し回数のための変数です。
while文の条件式には、「変数numが5ではない」という条件式を記述しています。そのため、(1)でnumに5が格納されてないならば、次の繰り返し処理が実行されます。
このように、while文では繰り返し回数が一定でない場合の処理を記述することが可能です。
配列を作る方法
先ほどのサンプルではランラムな数を直接コンソールに出力するプログラムでした。メソッドにして配列を取得することが出来るか考えて、以下のように別のサンプルを作りました。
ソース
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
public class Test002 {
public static void main(String[] args) {
Test002 t = new Test002();
t.test1();
t.test2();
}
public void test1() {
Integer[] values = getRandomValues1();
System.out.println("Integer型の配列");
System.out.println(values);
System.out.println(Arrays.toString(values));
}
public void test2() {
int[] values = getRandomValues2();
System.out.println("int型の配列");
System.out.println(values);
System.out.println(Arrays.toString(values));
}
public Integer[] getRandomValues1() {
Random random = new Random();
int num = 0; // 乱数格納用変数
// (1)
ArrayList<Integer> values = new ArrayList<>();
while (num != 5) {
// (2)
num = random.nextInt(10);
// (3)
values.add(num);
}
return values.toArray(new Integer[0]);
}
public int[] getRandomValues2() {
Random random = new Random();
int num = 0;
ArrayList<Integer> values = new ArrayList<>();
while (num != 5) {
num = random.nextInt(10);
values.add(num);
}
// Stream APIでint型配列を返却
return values.stream().mapToInt(value -> value).toArray();
}
}
結果
Integer型の配列
[Ljava.lang.Integer;@123772c4
[8, 8, 2, 8, 9, 7, 5]
int型の配列
[I@768debd
[6, 3, 4, 4, 1, 0, 8, 4, 3, 3, 0, 3, 8, 3, 8, 7, 9, 4, 4, 6, 2, 2, 0, 6, 5]
上記サンプルではgetRandomValues1()メソッドを定義しています。Integerの配列でランラムな数を返却するように実行しました。ただし、最後は値5で終わるようにしています。
(1)では一時的に値を格納するためのArrayListを生成しています。繰り返し回数が一定でないため、自由に追加操作が可能なArrayListを使うのが適切だと思いました。
(2)ではランダムな値を取得しています。
(3)で取得したランダムな値をArrayListに追加しています。
リターン文ではtoArray()メソッドを呼び出すことで配列に変換しています。引数に指定した型の配列に変換されます。ここで指定する配列はnewを使って空の配列を指定しています。(API仕様書にあった指定方法を参考にしました。)
getRandomValues2()メソッドはint型配列を返却するように変更を加えた実装です。Stream APIの機能を使って、Listをint型配列に変換できました。mapToInt()メソッドでIntStreamを生成し、配列に変換しています。
以上、参考になれば幸いです。