条件分岐 (if-else)

コンソール入力を行うプログラム

先週までのプログラムは常に決まった値を出力するプログラムであった。しかし、実際のプログラムのほとんどはユーザが何らかの入力を行いそれを処理するものが多い。

今回はeclipseウィンドウの下部にあるコンソール (printやprintln命令で結果を表示していたエリア) からユーザがプログラムを入力し、それに対して処理を行うプログラムを作成する。

入力を行うプログラムの例

たとえば、整数をユーザが入力し、それをそのまま出力するという単純なプログラムを考える。

00: package j1.lesson03;
01: 
02: import java.io.*;
03: 
04: public class EchoInt {
05:     public static void main(String[] args) throws IOException {
06:         BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
07:         System.out.print("input:");
08:         int input = Integer.parseInt(reader.readLine());
09:         
10:         System.out.println(input);
11:     }
12: }

一度に多くの新しいことが出てきたが、これらのほとんどは今はわからなくてよい。

このプログラムを実行させると、次のようにコンソール画面が表示される。


上記画面で、(1) "input:" というのは7行目に出現した

System.out.print("input:");

という命令を実行した結果である。この命令を実行後、プログラムは8行目で一時的に停止して、コンソール画面へのユーザの入力を待っている。この状態を終了させる場合、(2)にある四角い赤いボタンをクリックすればよい。ただし、プログラムは強制終了されて10行目まで到達しない。

ユーザがここに入力を行う場合、 "input:" と表示されている部分の少し右あたりをマウスでクリックする。ここで整数を入力しEnterキーを押すとプログラムが再開される。

例として、ここに 50 という数値を入力すると、以下のように表示される。


入力を行うプログラムの骨格

入力を行うプログラムは、以下のような骨格を持つべきである。

01: package [パッケージ名 (j1.lesson03など)];
02: 
03: import java.io.*;
04: 
05: public class [クラス名 (Helloなど)] {
06:     public static void main(String[] args) throws IOException {
07:         BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
08: 
09:         // 以下にプログラムを書く
10:    }
11: }

これ以降に命令を書くことによって (もちろん、mainメソッドの外に命令を書いてはいけない)、コンソールからの入力を取得することができる。

7行目には以下のような文がある。

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

これはBufferedReader型変数readerの宣言と初期化を同時に行っている (int a = 10;のようなもの)。

そのため、以下のようにも書ける。

BufferedReader reader;
reader = new BufferedReader(new InputStreamReader(System.in));

上記の例では、BufferedReader型の変数readerを用意して、そのあとにその変数に値を代入している。代入した値は今は理解しなくて良い。

これは入力を取得するための下準備であり、実際に入力を取得する命令ではない。次の項では実際に入力を取得する命令を紹介する。

入力を取得する命令

入力を取得する手段は多数あるが、ここでは単純な2つの命令を紹介する。

コンソールに入力された整数を取得する命令

先のプログラムにも出てきたが、コンソールに入力された整数を取得する命令は以下のように書ける。

int input = Integer.parseInt(reader.readLine());

これは単純に、int型の変数 input に、コンソールからの入力結果を 代入している だけである。そのため、変数の宣言と代入を別々に行うこともできる。

int input;
input = Integer.parseInt(reader.readLine());

また、この変数 input の名前は何でもよく、次のようなプログラムも書ける。

package j1.lesson03;

import java.io.*;

public class EchoTwoInt {

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("input (a):");
        int a = Integer.parseInt(reader.readLine());
        System.out.print("input (b):");
        int b = Integer.parseInt(reader.readLine());
        
        System.out.println("aの値は" + a);
        System.out.println("bの値は" + b);
        
    }
}

上記のプログラムは、コンソールに2回入力を行い、それぞれ入力された値を出力している。一つ目の入力を 100、二つ目の入力を 200 とした場合、結果は以下のようになる。

input (a):100
input (b):200
aの値は100
bの値は200

注意すべき点は、数値の入力を行う際に 半角モード (英数字を入力するモード、キーボード左上の 半角/全角 キーで切り替え) で行う必要があるという点である。全角で入力した場合、赤い文字でエラーが表示される。

コンソールに入力された実数を取得する命令

コンソールには整数だけでなく、実数も入力することができる。

double input = Double.parseDouble(reader.readLine());

これも整数のときと同様、double型の変数 input に、コンソールからの入力結果を 代入している だけである。よって、この変数 input の名前は何でもよい。

実数の入力を取得するプログラムとしては、以下のような例が挙げられる。

package j1.lesson03;

import java.io.*;

public class EchoDouble {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("実数をひとつ入力してください:");
        double input = Double.parseDouble(reader.readLine());
        
        System.out.println("入力された実数は" + input);
    }
}

このプログラムを実行し、一つ目の入力を 3.14 とした場合は、次のような結果が出力される

実数をひとつ入力してください:3.14
入力された実数は3.14

入力された値を使用する

入力された値は上記の例では変数に代入した。よって、入力が代入された変数は今後、通常の変数として扱ってよい。

条件判定を行うプログラム

if 文 (if statement)

今までのプログラムでは、書いてあるものを順に実行するだけであった。計算機の威力は、条件によって違う実行をすることによって発揮される。その基本的なものが、条件式の値によって選択的に実行する条件文である。たとえば、

if ( a > 0 )
    b = a * 3;

と書くと、aの値が0より大きいときだけ代入文b = a * 3;が実行される。より詳しく言うと、a > 0は条件式であり、条件式はboolean型の値(trueかfalseのどちらか)をとる。aの値が0より大きいとき条件式a > 0の値はtrueとなり、そうでないときfalseとなる。この「>」は比較演算子と呼ばれる。比較演算子(を使った条件式)には次のものがある

条件式 意味
a == b aとbが等しければtrue、そうでなければfalse
a != b aとbが等しくなければtrue、そうでなければfalse
a >= b aがbより大きいか等しければtrue、そうでなければfalse
a <= b aがbより小さいか等しければtrue、そうでなければfalse
a > b aがbより大きいければtrue、そうでなければfalse
a < b aがbより小さければtrue、そうでなければfalse

ここで注意すべき点は、

if ( a > b > c )
  ...

のように、3つ以上の値の比較は行えないという点である。これと同じ動作をさせる方法は、次週以降で紹介する。

if 文では if に続く () の中の条件式を計算した結果が、 true になれば (つまり、成立すれば) 次の命令を実行するという意味を持っている。上記の例では、変数 a の中身が 0 より大きければ a > 0 が true となり、b = a * 3が実行される。

もし、「aが0より大きい」ではなく、「aが0以上」という条件にしたい場合、次のように書けばよい。

if ( a >= 0 )
    b = a * 3;

これを、もし日本語で書くとしたら以下のようになる。

もし (a が 0 以上) ならば、b に a * 3 を代入する

if-else 文 (if-else statement)

if 文では、「条件が成立したとき」の処理を記述できた。他にも「条件が成立しなかったとき」を考慮した処理を記述する機構も用意されている。

if ( a > 0 )
    b = a * 3;
else
    b = 0;

上記の一連の命令列は、「aの値が0より大きいときだけ代入文b = a * 3;が実行され、そうでない場合は代入文b = 0が実行される」という意味を表す。

このように、ifに対してelseを用意することで、ifの判定が失敗した場合の処理を記述することができる。

これは、日本語で書くとしたら以下のようになる。

もし (a が 0 より大きい) ならば、b に a * 3 を代入し、
そうでないときには、b に 0 を代入する。

if文(if statement)を理解する

if ( a > 0 )
    b = a * 3;
else
    b = 5;

は、a > 0 の値がtrueのときb = a * 3;を実行し、falseのときb = 5;を実行するif文である。trueやfalseのとき実行させたい文が1つだけでなく複数ある場合はそれらを「{」と「}」で囲めばよい。いくつかの文を「{」と「}」で囲んだものはブロック(block)と呼ばれる。たとえば

if ( a > 0 ) {
    b = a * 3;
    d = b + 8;
} else
   b = 5;

などと書けばよい。

else 以降に続く命令文を2行以上のものにしたい場合も、以下のようにブロックで括ればよい。

if ( a > 0 ) {
    b = a * 3;
    d = b + 8;
} else {
   b = 5;
   d = 6;
}

ブロック内に書くことのできる命令は、0個以上の命令である。つまり、ブロック内には1つも命令を書かなくても、1つだけ命令を書いてもよい。

if ( a > 0 ) {
    b = a * 3;
} else {
}

上記の場合は、else以降が無意味である。

一般に

if (条件式A) {
  (命令文)
} else { 
  (命令文)
}

は、Aの値がtrueであるとき最初の{(命令文)}を実行する。そうでないときは、elseに続いている{(命令文)}を実行する。実は、ブロックも文の一種である。したがって、if文は

if (条件式)
    文 

または

if (条件式)
    文
else 
    文

の形である。それぞれ、「文」(statement)が1つであることに注意して欲しい。たとえば、

a = 1;
if (a >1 )
    System.out.println("a > 1");
    System.out.println("です");
else
    System.out.println("a > 1");
    System.out.println("ではありません");

は間違ったプログラムである。このプログラムは次のように解釈される。

a = 1  // これは代入文
if (a >1 )
    System.out.println("a > 1");  // ここまででif文が終わり
    System.out.println("です");  // これはif文の次に実行される文
else   // ここで、elseで始まる文はないのでエラーとなる。
    System.out.println("a > 1");
    System.out.println("ではありません");

分岐のあるプログラムを読む

以下のプログラムを読んで、どんなプログラムか考えてみること。

package j1.lesson03;

import java.io.*;

public class Umbrella {

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("降水確率を入力してください:");
        int chanceOfRain = Integer.parseInt(reader.readLine());
        
        System.out.println("降水確率は" + chanceOfRain + "% です。");

        if (chanceOfRain >= 50)
            System.out.println("傘を忘れずに。");
        else
            System.out.println("傘はいりません。");
       
        System.out.println("いってらっしゃい。");
    }
}
このプログラムはまず、
「__________________________」 と表示したのちにコンソールからの入力を取得し、

「降水確率は n % です。」と表示する。ただし、ここの n には 「__________」 が入る。

その後、入力された値が ________________ ならば 「傘を忘れずに。」と表示し、

そうでない場合は「傘はいりません。」と表示する。

最後に 「__________________________」 と表示して終了する。

ただし、このプログラムでは、降水確率に0より小さい値100より大きい値を入力した場合を考慮していない。以降ではそのような入力を判定する方法を紹介する。

if文の連鎖 (if-chain)

if ( A1 ) 
    B1
else
    if ( A2 )
        B2
    else
        B3

という文で、A1とA2は条件式、B1、B2、B3は1つの文または複数の文をまとめたブロックであるとする。これは、A1がtrueならB1、A1がfalseでかつA2がtrueならB2、A1がfalseでかつA2がfalseならB3を実行するif文である。これは通常

if ( A1 ) 
    B1
else if ( A2 )
    B2
else
    B3

の形に書くことが多い。条件によって3つの場合分けをすることになるからである。

なぜこれが3つの場合分けになるか不安な場合、ベン図を書いてみるとわかりやすい。

文章で簡単に説明すると次のようになる。

if ( A1 ) {
    // B1 が実行される条件 (A1がtrue)
     
    B1
}
else {
    // B2 または B3 が実行される条件 (A1がfalse)
    
    if ( A2 ) {
        // B2 が実行される条件 (A1がfalseかつA2がtrue)
        B2
    }
    else {
        // B3 が実行される条件 (A1がfalseかつA2がfalse)
        B3
    }
}

3つの場合分けの例を示すと、たとえば

if ( a < 0 ) 
    B1
else if ( a < 100 )
    B2
else
    B3

と書けば、a < 0のときB1、0 <= a < 100のときB2、100 <= aのときB3を実行することになる。これもわかりにくければ、数直線を書いてみるとよい。

この書き方で、先ほどのプログラムのif文を書き換えて、

if (n > 100)
    System.out.println("降水確率は0~100でなければなりません。");
else if (n >= 50)
     System.out.println("傘を忘れずに。");
else
     System.out.println("傘はいりません。");

とすれば、大きすぎる降水確率を入力したときに注意してあげること出来る。

ところで、間違って降水確率として負の数を入れた場合にはどうなるであろうか。このプログラムでは、その場合には注意されない。その場合にも注意するためには、次のようにすればよい。

if (n > 100)
     System.out.println("降水確率は0~100でなければなりません。");
else if (n < 0)
     System.out.println("降水確率は0~100でなければなりません。");
else if (n >= 50)
     System.out.println("傘を忘れずにね。");
else
     System.out.println("傘はいりません。");

このようにelse ifを何回か使ってたくさんの場合分けをすることが出来る。