コメントと制御文でJavaプログラムに“命”を吹き込め!携帯アプリを作って学ぶJava文法の基礎(4)(2/3 ページ)

» 2008年04月15日 00時00分 公開
[緒方聡エスマテック株式会社]

「while」文はもしそうならこれを繰り返す

 「while」文は「もしそうならこれを繰り返す」というような繰り返しを行う制御構文です。

 構文は以下のようになります。

 「while」は「繰り返す」で、繰り返し条件は「もしこうなら」で、文が「これを」に当たります。

while (繰り返し条件) 文

 Trimisでは、「while」文は2カ所で使用しています。1つは74行目で、これは以下のように書かれています。

74     while (true) {

 この場合、繰り返し条件は常にtrueなので、無限に繰り返します。無限に繰り返す文を「無限ループ」と呼びます。無限ループは、特にゲームプログラミングでは多用します。

 もう1つの「while」文は116行目です。その前後を以下に引用します。

115     } else if (key == 'U') {
116
        while (!isHit(x, y, current)) {
117
            y++;
118
        }
119
    }

 上記は、ブロックを落とす際に[上]キーが押された場合、一気に一番下まで落とす「ハードドロップ」の処理を表したものです。以下の図2は、分かりやすくなるようにGIFアニメーションにしたものです。

図2 while文を使用したハードドロップ 図2 while文を使用したハードドロップ

 「isHit」というメソッドは、落下中のブロックが積み上げられているブロックにめり込んでいるかどうかを判定するメソッドで、めり込んでいる場合はtrueを、そうでない場合はfalseを返します。

 繰り返し条件の先頭にある「!」は、「否定」を意味する起動で、この場合は「めり込んでいなければ〜」となります。

 y座標をどんどん増やしていけば、どんどんブロックが下に進み、いずれはめり込む、という仕組みを利用して、ハードドロップを処理しています。

 図2のGIFアニメーションみたいにブロックがめり込んでしまったらまずいんじゃないか、と考えるのは正しい意見です。めり込んだ場合の処理は120行目のif文の中で行っており、どういうめり込み方だったのかによって、処理を変えているのですが、ハードドロップでめり込んだ場合は、143行目からのif文の内部で処理しています。

143 } else if (key == 'D' || key == 'U') {
144     y--;
145     fix = true;
146 }

 y座標を1つ戻しています(「y--;」は「y = y - 1;」と同じ意味を持っています)。

do」文は取りあえずやってみる

 「do」文は「繰り返しなんだけど、取りあえず1回はやってみる」という制御構文です。構文は以下のようになります。

do {
    
} while (繰り返し条件);

 「while」文と似ていますが、1回だけは文が実行されるのが特徴です。while文は「文を実行するかどうかを最初に判定して、それから文を実行し、また文を実行するかどうか判定する」のに対し、「do」文は「最初に1回だけ文を実行し、その後また文を実行するかどうかを判定する」という動作をします。

 使い分けの例を見てみましょう。車にガソリンを入れる場合、「while」文なら「満タンかどうかを確認して、満タンじゃなければ1リットルガソリンを入れる」となるのに対し、「do」文は「取りあえず1リットル入れてみて、満タンになってないなら〜」となります。「do」文は無条件で1回目の処理を行うため、その処理を行う前提条件が整っている場合に使用することになります。この場合は、1リットル分のガソリンはその時点で減っているはずだ、などです。

 Trimisでは、使用していません。「do」文は一般的にも使用機会が低いと思います。

「for」文は決めた条件を確認しながら繰り返す

 「for」文というのは「決めた条件を更新・確認しながら繰り返す」というような繰り返しを行うための制御構文です。構文は以下のようになります。

for (初期化; 繰り返し条件; 更新) 文

 上記構文の説明の前に、まずは実際のコードを見てみましょう。232行目の「copy」というメソッド全体を見てみます。

232 void copy(int[][] src, int[][] dest) {
233     for (int i = 0; i < src.length; i++) {
234         System.arraycopy(src[i], 0, dest[i], 0, src[i].length);
235     }
236 }

 このメソッドは1つの「for」文だけで構成されていることが分かります。メソッドの名前からすると、何かをコピーしたいわけですが、何をコピーしたいかというと、このメソッドに渡された引数srcを、引数destにコピーしたいのです。

 では、このコピーの仕組みを順番に見てみましょう。

 まずは、「初期化」部分です。コードでは「int i = 0;」というふうに、「i」という変数を作成し、値を0で初期化しています。

 次に、「繰り返し条件」部分です。コードでは、「i < src.length;」となっており、これは「iの値がsrcという配列の長さよりも小さい場合」という意味になります。この繰り返し条件は、繰り返しの最初に判定します。

 次は、「更新」部分です。「i++」はiの値を1つ増やしています。この更新部分は、繰り返しごとの最後に実行されます。

 最後に、文の部分です。これは、配列を別の配列にコピーする処理を行っています。iの値が最初は0で、繰り返しごとに1ずつ増えていき、配列の長さ未満であれば繰り返すため、配列全体がコピーされる、というのが理解できるのではないかと思います。

 for文は繰り返しの中でも利用頻度が高いでしょう。そして、配列と組み合わせて使用することが多いのも特徴です。Trimisでは24カ所でfor文を使用していて、20カ所は配列と組み合わせて使用しています。

 次ページではさらに、処理の途中で一気にジャンプする「break」「continue」「return」について説明します。

コラム 「拡張forループとは?」

for文は配列と組み合わせて使用されることが多いのですが、さらにいうと、配列の全要素を逐次的に処理することが多いため(Trimisの配列と組み合わせている20カ所は、そのすべてが配列の全要素への逐次処理です)、Javaでは新しく「拡張forループ」というものが用意されました。

配列の全要素を出力する処理は、for文では以下のようになります。

int[] foo = {0, 1, 2, 3, 4};
for (int i = 0; i < foo.length; i++) {
    System.out.println(foo[i]);
}

これに対し、拡張forループでは、以下のように記述します。

int[] foo = {0, 1, 2, 3, 4};
for (int i : foo) {
    System.out.println(i);
}

自明処理である、ループカウンタの初期化やインクリメントや比較などを省略し、すっきり記述できています。残念ながら、拡張forループはケータイJavaではいまのところ使用できません

なお、拡張forループは「for-eachループ」とも呼ばれますが、どちらも間違いではありません。


Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。