Javaプログラミング基礎 講義資料

if 文

今回の主なテーマは条件判定です。 これはプログラムの実行の途中で、 変数の値を比較し判断することでプログラムの動作を決めることができるものです。 条件判定がないと、プログラムは決められたことを順番に行うことしかできないため、 あまり意味のある仕事をすることができませんが、 条件判定があると、だいぶ複雑な処理を記述することができるようになります。

日本語の「もしも〜ならば〜」をプログラムで表現する

教科書 pp.84-87 も同時に参照してください。

日本語の「もしも〜ならば〜」という文章をプログラムで表現するために、 条件判定を行う基本的な方法が if 文です。 if 文には 2 つの形式があります。1 つめの形式は次のとおりです。

if文の構造(1)

「式」の部分に書く式とは、比較を行って条件を満たす/満たさないを判定するような式です。

まず最初に条件の式を計算して、その結果 (成立、不成立) を求めます。 次に成立した場合に限り、その次の文を実行します。 成立しない場合は文は実行せず、そのままで終わりとします。

if (x > 0)
    System.out.println("x is positive.");

この if 文は、最初に x > 0 の計算を行います。 この条件式は、 x が 0 より大きければ 条件が成立したとし、そうでなければ (x が 0 または負) 、 条件が成立しなかったとします。 x が 0 より大きければ、 if の後の System.out.println が実行され、 x is positive. と表示することになります。 一方、x が 0 または 負の数であれば何も表示しません (数学と同様に「>」と「≧」の違いに注意しましょう) 。

日本語の「もし〜ならば〜。そうでなければ〜。」をプログラムで表現する

教科書 pp.88-90 も同時に参照してください。

次に、「もし〜ならば〜。そうでなければ〜。」をプログラムで表現するための、 if文の第2の形式について説明します。

if文の構造(2)

if 文の第 2 の形式は次のような動作をします。 最初に式を計算して、条件が成立するかどうかを求めます。 成立すれば if の次の文を実行し、 成立しなければ else の次の文を実行します。

次の if 文を考えてみましょう。

if (x == y) 
    System.out.println("x is equal to y.");
else
    System.out.println("x is not equal to y.");

この if 文は、最初に x == y の計算を行います。 もし、x と y が等しければ、 if の後の最初 System.out.println が実行され、 x is equal to y. と表示することになります。 一方、x と y が等くなければ、 else の前の文は実行せず、 else の後の System.out.println だけを実行します。 結果として、x is not equal to y. と表示することになります。

文について

if 文の形式を説明する際に「文」という言葉を用いましたが、 ここで文について正確に説明します。

これまで、 プログラムの中に書いた代入や、System.out.println などが上から順に実行されると学んできました。 これらの代入や System.out.println などを 「文」と呼びます。 また、セミコロンも文の一部です (文のあとに何かおまけの記号が付いていると考えてはいけません) 。

if 文の中には、 1 つの文しか書くことができません。 複数の文を書きたい場合、 複数の文を並べたものをグループとして 1 つにまとめ、 全体を 1 つの文のように扱う方法が用意されています。 これを複合文、またはブロックと呼びます。 書き方は次のとおりです。

{
    文
    文
    ...
    ...
    文
}

if 文の中で複数の文を書きたい場合、たとえば、

if (x > 0) {
    y = x;
    System.out.println("x is positive.");
}

のように、ブロックを用いて書くことができます。

(教科書 pp.137-138 にも解説あり)

二重のif文

if文を二重に書くことができます。 if文の中に書くことができるものは「文」であり、 またif文自体も「文」の一種だからです。

if (x > 0)                      // x > 0 が成立するなら
    if (x % 2 == 0) 
        System.out.println("正の偶数");
    else
        System.out.println("正の奇数");
else                               // x > 0 が成立しないなら
    if (x % 2 == 0) 
        System.out.println("0または負の偶数");
    else
        System.out.println("負の奇数");

比較演算子

教科書 p.86 Table 4-1 も同時に参照してください。

if 文の形式の中の「式」と書いた部分には、 条件が成立するか成立しないか判定するような式を書きます。 この式とは、yes か no か、成功か失敗か、正しいか正しくないか、 というように 2 つに 1 つの結論を出すようなものです。

Java では、条件が成立したかどうかを示すために、 成立した場合を「真 (true)」、成立しなかった場合を「偽 (false)」 という表し方をします。

演算子 意味
== 等しければ true、等しくなければ false
!= 等しくなければ true、等しければ false
< 小さければ true、そうでなければ false
<= 小さいまたは等しければ true、そうでなければ false
> 大きければ true、そうでなければ false
>= 大きいまたは等しければ true、そうでなければ false

これらの演算子は、その左右に書いた式の値を比較して true か false の結果を出します。

特に、代入の = と、比較の == の使い間違いに注意が必要です。 数学の世界ではイコールは、2 つの値が等しいという意味で使われますが、 Java の世界では、= は代入で、 2 つの値が等しいことを示すには == を使う必要があります。

いくつか例を示します。

x == 0
x + y > 3 * z

2 つめの例は、x + y と 3 * z を計算し、前者が大きい場合 true となります。 このように比較の中に複雑な式を書くこともできます。

条件判定の and/or

教科書 pp.95-100 を参照してください。

複数の条件を組み合わせて、より複雑な条件式を書くことができます。 2 つの条件式を組み合わせて複雑な条件をつくるために、 「かつ」や「または」などの意味を持つ演算子があります。

演算子 意味
&& 「〜かつ〜」 論理演算としての and
|| 「〜または〜」 論理演算としての or
! 「〜ではない」 論理演算としての not

例えば、x が 1 〜 10 の範囲内にあるかどうかを 表す条件を考えてみましょう。 数学の世界では 0 ≦ x ≦ 10 と表しますが、 Java ではこれをそのまま次のように書くのは誤りです。

if (1 <= x <= 10)
    .....

Java では、比較を行う演算子は常に左辺と右辺の 2 つの値の比較を 行います。上のように 3 つの値 (1, x, 10) をいっぺんに比較することはできません。次のように書くのが正解です。

if (1 <= x && x <= 10)
    .....

これを言葉で表すと 「x が 1 以上 かつ x が 10 以下」 となります。

このように、言葉や数学の世界での表現は プログラムでの条件式の意味と異なる場合があります。 例えば、「x が a または b に等しい」 という言い方をそのまま訳して x == a || b と書くのは間違いです。 この場合は、日本語を 「x が a に等しい、または x が b に等しい」 と言わなければならないのです。 これを訳して x == a || x == b とするのが正解です。

例題: 3つの整数から最大値を求める

3 つの値 x, y, z の最大値を求めて出力するプログラム例を 3 とおり示します。 同じ仕事をするプログラムでありながら、 少しずつ違う書き方になっています。 if 文の使い方としてよく現れる書き方も含まれているので、 それらの点に注目しましょう。

1. 変数の比較だけを行う方式

最初に示すプログラムは、 3 つの変数の値を 2 つずつ比較して、 最大のものを見つけようという方針です。

public class Max3a {
    public static void main(String[] args) {
	int x = 5;
	int y = 2;
	int z = 3;
	int max;

	if (x > y)
	    if (x > z)
		max = x;
	    else
		max = z;
	else
	    if (y > z)
		max = y;
	    else
		max = z;

	System.out.println("最大値は " + max + " です");

    }
}

最初に x と y を比較する if 文があります。 x が大きければ、 else の前の文を実行します。 この場合の else の前の文とは、 if (x > z) max = x; else max = z; 全体です。 また、 else の後の文は、 if (y > z) max = x; else max = z; 全体です。
(if 文全体を一つの文として扱うということを思い出してください。)

x が y より大きければ、 x と z の大きい方が最大となります。 そうでなければ (y が x 以上であれば) 、 y と z の大きい方が最大となります。 内側の if 文で、 x と z または、 y と z の大きい方を変数 max に代入していま す。

この方法は実はあまり勧められるものではありません。 変数が 3 つだから良いようなものの、 変数の数が増えると条件分岐が複雑になってしまうからです。

2. and を使う方法

次のプログラムは、起こり得るすべての条件を and で結び記述したものです。

public class Max3b {
    public static void main(String[] args) {
	int x = 5;
	int y = 2;
	int z = 3;
	int max;

	if (x >= y && x >= z)
	    max = x;
	else if (y >= x && y >= z)
	    max = y;
	else
	    max = z;

	System.out.println("最大値は " + max + " です");

    }
}

最初の if 文では、 x が y よりも大きく、 なおかつ x が z よりも大きいとき、 max に x の値を代入します。

else の後の if 文も同様に、 y が最大のときの動作を記述しています。 最後の else以降は、 x が最大でもなく y が最大でもない、 つまり z が最大の場合を記述しています。
この書き方も、やはり変数の数が増えると条件が複雑になる欠点があります。

ただし、教科書 p.92 の例題のように、 実際のプログラムでは、

if ( 条件1 )
        文1
else if ( 条件2 )
        文2
……
else if ( 条件k-1 )
        文k-1
else
        文k

という書き方はよく用いられます。

これは、先頭から条件1、条件2、 …と順に計算していって、最初に真 (true) になった条件i に対応する文iだけ実行するという意味です。 条件k-1まで、すべて偽 (false) であれば、 最後の文kを実行します。

3. 変数に途中までの最大値を代入していく方法

public class Max3c {
    public static void main(String[] args) {
	int x = 5;
	int y = 2;
	int z = 3;
	int max;

	max = x;
	if (y > max)
	    max = y;
	if (z > max)
	    max = z;

	System.out.println("最大値は " + max + " です");

    }
}

最大値を求めるプログラムとしては、これがお勧めです。 変数 x, y, z を一つずつ max と比較して、 もし大きければ、その値を max に代入していきます。

こうすることによって、その時点までに調べた変数の中での最大値が max に常時格納されていることになります。 この操作を最後の変数までくり返せば、全体の最大値が得られます。

このプログラムの書き方であれば、 変数の個数が少しくらい増えても見通しの良いプログラムになります。

演算子のあれこれ

Java では、式には一般的な四則演算の他に様々な計算式を書くことができます。

剰余演算

剰余とは「余り」のことです。 整数で割り算を行った結果の余りを計算するには、 % (パーセント) を使います。

次の例は変数 b の値を 2 で割ったときの余りを求める式です。 この式の計算結果が0ならbは偶数、1ならbは奇数ということになります。

a = b % 2;

増分、減分演算子

次のような式を考えてみましょう。

a = a + 1;

この式の意味は、元の a に 1 を加え新たに aに代入する、ということです。 すなわち、元の a を 1 増やすという働きをする式です。

Java では、変数の値を 1 増やしたり、1 減らしたりする働きを持つ ++, -- という演算子が用意されています。 先ほどの例と、

a++;

は同じことになります。また ++a と書いても構いません。

-- 演算子は、指定された変数の値を 1 減らすことを行います。 a = a - 1 という式は a--; と同じことです。

++ や -- を用いると、変数名を 1 回しか書かなくて済むし、 1 だけ増やす (減らす) という意味を明確に表現することができます。

a++ も ++a も、主な目的は変数の値を変化させることですが、 式である以上、これらも値を持っています。 a++ と ++a の違いは、 a++ の値が変化させる前の古い a の値であるのに対し、 ++a は変化させたあとの新しい a の値であるということです。

たとえば、a の値が 5 であったとき、

b = a++;

とした場合、 b の値は 5 となり、

b = ++a;

とすれば b の値は 6 となります。

実際のソフトウェアでは、 変数の値を 1 ずつ増やしながら順番に仕事をしていく、 ということが良く行われます。 変数の値を 1 増やすことをインクリメント (increment) 、 1 減らすことをデクリメント (decrement) と言います。

複合代入

次のようなプログラムを考えてみます。

a = a + 10;

この式の意味は、元々の a の値を 10 増やすということです。 このような式も次のように書くことができます。

a += 10;

この書き方は + だけに限らず、 他の四則演算や余剰 (%) などに対して適用できます。