if文

条件分岐

条件分岐とは、「もし○○ならば、~~する」という関係が成り立つ処理を、プログラムで表現することを言います。
条件にあてはまるかどうかで、処理を実行するかどうかを変えることができます。

これまで見てきたプログラムでは、基本的に上から順に全てのコードが実行されていました。
しかし、実際のプログラムを作成するにあたっては、様々な条件によって流れを変えたい(処理を実行するかどうかを変えたい)ケースがあり、その際には条件分岐を使用します。

if文~もし○○だったら~

条件分岐の最も基本的な文法が「if文」となります。

基本的な記法は、次のようになります。
基本的なif文では、判定したい条件式と、その条件が成立したときに実行するコードを記述します。

if ( 条件式 ){
  //条件が成立した場合の処理
}

判定したい条件を括弧内に書き、その下に条件が成立時(条件が正しい時)に実行したい処理を書きます。
条件には、単純な比較から、複雑な条件まで書くことができ、if文の利用範囲は広いです。

「com.cmps.ifsentence」パッケージを作成し、「If」クラスを作成して下さい。
次の例では、値が100以上かどうかを判定しています。
>= という記号は、「記号の(左側)が(右側)以上」かどうかを確認します。
実際に動かしてみましょう。

public static void main(String[] args) {
        int value = 300;
        if(value >= 100) {
            System.out.println("値は100より大きいです。");
        }
}

300 >= 100 は正しいので、
System.out.println("値は100より大きいです。"); が実行されて「値は100より大きいです」と出力されます。

今度は、valueの値を50に変えて実行してみましょう。
50 >= 100 となり正しくないため、実行結果はなにも出力されません。

結局、if文というのは、その条件がtrue(成立時)なのかfalse(不成立時)なのかということを判断しているのです。

<if文の条件式に書けるのはboolean型>
System.out.println( 4 + 5 );と書くと9と出力されますが、これは 4 + 5の処理の結果の値が9(int型)ということです。
>= を使用した場合、処理結果はboolean型となります。
試しに System.out.println( value >= 100 ); を記述すると、条件式の結果(trueまたはfalse)が出力されることを確認できます。

同じように、if文の条件に直接boolean型の値を入れても動作します。
次の処理を書いてみましょう。

boolean judge = true;
if(judge) {
  System.out.println("値は true(成立時)です");
}

if文で使える比較(関係)演算子

if文の条件式では、比較演算子がよく使われます。ここでは、if文で使われる比較演算子の種類を説明します。
なお、比較演算子が使えるのは数値のみとなっており、文字列の比較には別の処理が用いられます。(後述)

比較演算子の種類

比較演算子には、大小関係を比較する「<」「>」「<=」「>=」や、等値関係を比較する「==」「!=」があります。
次の表に比較演算子の一覧を記載します。

比較演算子意味
x < yxはyより小さい
xはy未満
x > yxはyより大きい
x <= yxはyより小さいか等しい
xはy以下
x >= yxはyより大きいか等しい
xはy以上
x == yxとyの値は等しい
x != yxとyの値は等しくない

*以上や以下の「以」は、「=」(等しい)を意味します。

以下のソースを記入して出力結果を確認してみましょう。

int num = 3;
int fig = 3;
int dig = 4;
          
// 例1  numとfigの値が等しいことを判定
if (num == fig) {
 System.out.println("numとfigの値は等しい");
} else {
 System.out.println("numとfigの値は等しくない");
}

// 例2  numとfigの値が等しくないことを判定
if (num != fig) {
 System.out.println("numとfigの値は等しくない");
} else {
 System.out.println("numとfigの値は等しい");
}

// 例3  numはdigより大きい
if (num > dig) {
 System.out.println("numはdigより大きい");
} else {
 System.out.println("numはdigより大きくない(等しいか小さい)");
}

// 例4 numはdigより小さい
if (num < dig) {
 System.out.println("numはdigより小さい");
} else {
 System.out.println("numはdigより小さくない(等しいか大きい)");
}

// 例5  numはfig以上
if (num >= fig) {
 System.out.println("numはfig以上");
} else {
 System.out.println("numはfig以上ではない(より小さい)");
}

// 例6  numはdig以上
if (num >= dig) {
 System.out.println("numはdig以上");
} else {
 System.out.println("numはdig以上ではない(より小さい)");
}

// 例7  numはfig以下
if (num <= fig) {
 System.out.println("numはfig以下");
} else {
 System.out.println("numはfig以下ではない(より大きい)");
}
// 例8  numはdig以下
if (num <= dig) {
 System.out.println("numはdig以下");
} else {
 System.out.println("numはdig以下ではない(より大きい)");
}

else(エルス)~ifが成立しなかったら~

いままでは条件が成立時の処理を見てきましたが、成立しない時に別の処理を実行したい場合はelse(エルス)を使用します。
次の処理を書いてみましょう。

int score = 50;
if (score > 100) {
 System.out.println("値は100より大きいです");
} else {
 System.out.println("値は100以下です");
}

このように処理を記述することにより、条件の成立時と不成立時のパターンをすべて網羅できるようになります。

なお、else文はif文がないとコンパイルエラーになりますが、if文はelse文がなくてもコンパイルエラーにはなりません。

else if(エルスイフ)~もし○○ではなく△△だったら~

if文の後に、さらに条件を分岐したいという場合があります。その場合はelse if (エルスイフ)を使用します。
次の処理を書いてみましょう。

int value0 = 300;
if (value0 > 500) { // 条件A
 System.out.println("値は500より大きいです");
} else if (value0 > 100) { // 条件B
 System.out.println("値は100より大きいです");
} else {
 System.out.println("値は100以下です");
}

この処理では、一番上の条件から順番に条件の確認が行われていきます。
最初の条件では「value0 > 500」の比較をして、条件に当てはまらないと判断されます。すると、次のelse if()の条件にある「value0 > 100」の比較を行います。

※補足
上記の条件A,Bの順序を反転して、条件Bを先に設置すると「value0 > 500」の条件が機能しなくなります。
例えば、value0の値が600の場合、条件B「value0 > 100」にあてはまるので、条件A「value0 > 500」が実行されることはありません。
上から条件を確認していったときに、一度条件に合致するものがあると、そこから後ろの条件は確認されません。

value0 = 300;
if (value0 > 100) { // 条件B
System.out.println("値は500より大きいです");
} else if (value0 > 500) { // 条件A:条件Bに含まれるので実行されることがない(この条件を通る可能性がない)
System.out.println("値は100より大きいです");
} else {
System.out.println("値は100以下です");
}


if句、else句は1つしか書けませんが、else if句は複数続けて記述することができます。
条件分岐を記述するとき、それぞれ if句:必須、else句:0~1つ、else-if句:0個以上 書けるということです。

value0 = 300;
if (value0 > 500) {
 System.out.println("値は500より大きいです");
} else if (value0 > 200) {
 System.out.println("値は200より大きいです");
} else if (value0 > 100) {
 System.out.println("値は100より大きいです");
} else {
 System.out.println("値は100以下です");
}

このようにelse ifを使用することにより、複数の条件を順次追加していくことが可能になります。

単一条件分岐の簡略化

以下のような条件文が一つしかない場合ブロック(中括弧、波括弧)を省略することができます。
次の処理を書いてみましょう。

int num = 300;
    
if (num > 100) System.out.println("値は100より大きいです");

これは通常のブロック{} を記載したif文と同じように動作します。
どちらも同じ動作ですが、プログラムコードを綺麗に見やすくするという観点から、臨機応変に選択しましょう。

ただし、一行で記述する場合の注意点があります。
{}を省略すると、目視でif文の終わりがわかりづらくなる

int testScore = 55;
        
if (testScore >= 60)
  System.out.println("合格です。");
if (testScore >= 60) {
  System.out.println("合格です。");
}
System.out.println(testScore);

このような文を見てみると、if文がどこからどこまでなのか、というのが分かりづらいです。
このわかりづらさというのは、現場ではミスを生む原因になりえます。
過去には、プログラミング言語は違いますが、Appleがこの波括弧を省略する記述方法を使用した際のミスにより、重大なセキュリティホールを作ってしまったことがあります。
参考サイト:AppleがiOS7.0.6で修正したSSLバグの簡単な解説

else句、elseif句がある場合はブロックを省略しないこと。

// ※NG例
if (testScore >= 60) System.out.println("合格です。");
else if (testScore >= 80) System.out.println("優秀です。");

三項演算子

else句がある場合で、一行で記述したい場合、 if文ではなく「三項演算子」を使って記述することができます。 次の処理を書いてみましょう。

int box = 1;
int answer;
// if文
if (box == 1) {
 answer = 10;
} else {
 answer = 20;
}
System.out.println(answer);

// 三項演算子
answer = (box == 1) ? 10:20;
System.out.println(answer);

このif文と三項演算子はどちらも同じように動作いたします。
変数boxの値を変えてみても、System.out.println(answer);の結果は常に同じになることが確認できると思います。

ただし、こちらも一行に省略しない方が良いケースがあります。

int hogehoge = 11;
String hoge;
// NG例:次のように条件文や処理文が長い場合は、一行にしない
if (hogehoge == 10 || hogehoge == 20 || hogehoge == 30 ) {
 hoge = "値は10または20または30です";
}

// NG例:一行にすると見にくい
if (hogehoge == 10 || hogehoge == 20 || hogehoge == 30 )  hoge = "値は10または20または30です";

何でも一行に省略すればいいという訳ではありません。条件文が長い場合や、 処理文が長い場合は可読性の点から一行にしないことをおすすめします。 エディターをはみ出てしまうことがあったら、目視でも確認しづらいためです。

また、三項演算子を使用する際は以下の点に留意しましょう。
これらは可読性の観点から守るようにしてください。

・三項演算子の結果欄( ? から : の間と、: から ; の間)には、処理を書かない。値や変数のみを返す形にする

 // 良くない例
int sampleNum = 1;
String sampleText = "1ではありません"
int result = (sampleNum == 1) ? System.out.println(sampleNum) : System.out.println(sampleText);//処理を書いている NG

// 良い例
result = ( sampleNum == 1) ? 1 : 0;//値を返す
System.out.println(result);

・条件式の部分を()で囲むこと
・三項演算子のネスト(重ねての使用)をしないこと

// 条件式の部分を()で囲むこと
ans = num == 1 ? 10 : 20;//()がないと読みづらい NG
ans = (num == 1) ? 10 : 20;

// 三項演算子のネスト(重ねての使用)をしないこと
ans = (num == 1) ? ((num > 1) ? 10 : 0) : 20;//誤読を招きやすい記述!NG

if文のネスト

if文は、多重にネストさせて記述することができます。
次の処理を書いてみましょう。

int value1 = 100;
int value2 = 200;
int value3 = 200;

if ( value1 < value2 ){//条件A
    System.out.println("value1よりvalue2が大きい");

    if ( value2 == value3 ){//条件B
        System.out.println("value2とvalue3は等しい");
    }
}

条件Bは条件Aのブロック内に入っているので、条件Aが成立時のみ条件 Bの比較も実行されます。(条件Aがfalseの場合、問答無用で条件Bも実行されない)

同様にelse if句やelse句内にも、if文やif-else文などをネストして書くこともできます。

ネストを使用すると、このように複雑な条件も組めるようになります。
ただし、if文のネストは、多用しすぎて何重にもif文が重なると処理が分かりづらくなります。
可読性やメンテンナンスの面からも、if文のネストは多用しすぎないように注意しましょう。

論理演算子

if文の条件式に、複数の条件の組合せを記述したいとき、論理演算子を使用します。
論理積「&&」、論理和「||」、論理否定「!」の各演算子の概要を説明し、コード例を示します。

論理積とは

複数の条件が全て成立しているときに実行したい処理がある場合には、論理積(&&)を用います。

「A && B」と書いたとき、「Aが正しく(true)、Bが正しい(true)時、trueを返す」という意味になります。
AもBも両方成立しているときのみtrueとなり、どちらかが不成立であればfalseとなります。

2つの条件式AとBの真偽の組合せにより、「A && B」の値がどうなるかを次の表に示します。

ABA && B
truetruetrue
truefalsefalse
falsetruefalse
falsefalsefalse

以下の処理を書いてみましょう

int month = 1;
int day = 5;

if (month == 1 && day <= 7) {
    // month == 1 と day <= 7 がtrueのときだけ実行
    System.out.println("あけましておめでとうございます");
} else {
    // それ以外のとき実行
    System.out.println("おはようございます");
}

このように複数の条件を一つのif文に記載することができ、論理積ではどちらの条件も満たしている場合のみtrueとなります。

論理和とは

複数の条件のいずれかが成立したときに実行したい処理がある場合には、論理和( || )を用います。

「A || B」と書いたとき、「Aが正しいか(true)、Bが正しい(true)時、trueを返す」という意味になります。
AかBのどちらかが成立していればtrueとなり、どちらも不成立のときのみfalseとなります。

2つの条件式AとBの真偽の組合せにより、「A || B」の値がどうなるかを次の表に示します。

ABA || B
truetruetrue
truefalsetrue
falsetruetrue
falsefalsefalse

論理和を使ったコードの例を次に示します。次の処理を書いてみましょう。

int month = 7;
if (month == 12 || month == 1 || month == 2 ) {// どれか1つを満たせば実行
    System.out.println("冬です。");
} else if (month == 3 || month == 4 || month == 5 ) {
    System.out.println("春です");
} else if (month == 6 || month == 7 || month == 8) {
    System.out.println("夏です");
} else if (month == 9 || month == 10 || month == 11) {
    System.out.println("秋です");
} else {
    System.out.println("月の値が不正です");
}

このように複数の条件を一つのif文に記載することができ、いずれか1つでも条件を満たしていればtrueとなります。

否定とは

ある条件が偽のときに実行したい処理がある場合には、否定演算( ! )を用います。

条件Aの真偽に対して、否定「! A」の値は、表のように逆の値になります。

A!A
truefalse
falsetrue

否定を使った例を次に示します。

int num = 5;

// 「否定」不使用パターン
if(num == 5){
  System.out.println("numの値は5です");
} else {
  System.out.println("numの値は5ではありません");
}

// 「否定」使用パターン
if(!(num == 5)){
  System.out.println("numの値は5ではありません");
} else {
  System.out.println("numの値は5です");
}

上記のコードでは、否定を使用したパターンと不使用のパターンの処理を記載しています。
numが5だった場合、否定不使用パターンではif文内の処理が出力されたのに対し、
否定使用パターンでは、else文内の処理が出力されていることが確認できると思います。

このように、否定を使うことでif文の条件を「○○でなかったら(上記でいえばnumが5でなかったら)」と設定することが出来るのです。

少し複雑な条件でも確認してみましょう。

このコードでは、月の値を示す変数monthが1以上12以下でない場合に、エラー処理を行います。
こちらも否定使用パターンと不使用パターンの2つの処理を記載しています。

int month = 13;
          
//「否定」不使用パターン
if (month >= 1 && month <= 12) {
 System.out.println("月の値は" + month);
} else {
 System.out.println("月の値が不正です");
}
           
//「否定」使用パターン
if (!(month >= 1 && month <= 12)) {
 System.out.println("月の値が不正です'");
} else {
 System.out.println("月の値は" + month);
}

この条件式 if (!(month >= 1 && month <= 12)) は、「monthが1未満または12より大きい」(if (month < 1 || month > 12))と記述しても同じですが、正常な値である「1以上12以下」の条件に否定をつけることで、わかりやすくしています。

このように「!マーク」以外の式は同じであるのに対し、
否定を不使用パターンでは「1~12の間ですよね~」という風な条件ですが
否定を使用パターンでは「1~12ではないですよね~」という風な条件に変わるのです。

反対に、否定を使用して等しい条件式として働かせるには以下のように書き換えます。
下記の例におけるAとBの条件式は等しい挙動をします。
変数x の値を変えて確認してみると同じ出力結果になることが確認できます。

int x = 1;
//「否定」不使用パターン
if (x <= 1 && x > 3) {            //A
 System.out.println("条件式A:true");
} else {
 System.out.println("条件式A:false");
}
           
//「否定」使用パターン
if (!(x > 1 || x <= 3)) {         //B
 System.out.println("条件式B:true");
}else {
 System.out.println("条件式B:false");
}

数直線で図示すると以下のようになります!
否定をつけて、()の中の比較演算子と論理演算子を反転すると、同じ条件になります。
・|| であれば &&に。&&を||に
・>= を< に(=の有無も反転)

文字列の比較(String.equals(String s))

比較演算子 == は、文字列(String オブジェクト)の比較には使用することはできません。
代わりに、文字列に対して使用できるequalsメソッドを使用します。

以下のソースを記入して、出力結果を確認してみましょう。

String example1 = "Hello";
String example2 = "Hello";
example1 += " World";
example2 += " World";
          
// NGパターン
if(example1 == example2) {
 System.out.println("example1とexample2は等しい");
} else {
 System.out.println("example1とexample2は異なる");
}

// OKパターン
if(example1.equals(example2)) {
 System.out.println("example1とexample2は等しい");
} else {
 System.out.println("example1とexample2は異なる");
}

example1にもexample2にも「Hello World」が格納されており、比較で「Hello World」と「Hello World」が一致しているかどうかを見ているように見えますが、実際は全く異なる比較を行っており、文字列の比較時に「==」はfalseとなります。

文字列は生成されると、メモリ上に文字列を保存しておくための場所が確保されます。example1やexample2は、値を保存しているわけではなく、確保された場所を保持しています。場所を覚えておきexample1やexample2を使う際にその場所をたどって値を引っ張り出してくるという仕組みになっています。
※値が置いてある場所を示す値を保持する変数を参照型変数といいます。

この参照という仕組みがあるため「==」で比較した場合、文字列の値が一緒かどうかではなく、文字列がメモリ上で格納されている場所が一緒かどうかという比較になります。
(※(文字列==文字列)と書いたとき、システム側がメモリの節約として気を利かせて判定してくれる場合もありますが、常に正しく判定できるとは限らないのでやはり使用すべきではありません)

OKパターンで使用しているString.equalsでは正しく文字同士の比較を行えるため、上手く動作します。
数字の比較では比較演算子、
文字列の比較ではequasl()を使う と覚えておきましょう。

equasメソッドの記述方法

文字列1.equals(文字列2)

string1に該当する文字列とstring2に該当する文字列を比較した結果を返却します。

練習問題

「com.cmps.ifsentence」パッケージ内に「IfQuestion」クラスを作成してください。

問1: 値が100以下の場合、「値は100以下です。」と表示する。

問2: 値が「ABC」でない場合、「値はABCではありません。」と表示する。

問3: 値が50以上かつ100以下の場合、「値は50~100の間です。」と表示する。

問4: 「問3」を簡略化して書きましょう。
  ※「単一条件分岐の簡略化」を使用します。問3ですでに簡略化してる場合は飛ばして大丈夫です。

問5: 値が100の場合、「合格!」と表示する。それ以外の場合は「不合格!」と表示する。

問6: 値が100の場合、「満点!」75以上は「合格!」それ以外の場合は「不合格!」と表示する。

問7: 値が75以上は「合格!」それ以外の場合は「不合格!」と表示し、かつ100の場合、「満点!」0の場合、「0点!」と表示する。

問8: 下記の条件式部分(※A、B、C、D、E)を簡潔に書き換えてください。条件にともない場所を変更してもかまいません。

int month = 7; // 0~13のランダムな整数が来ると想定してください
        
if (month == 12 || month == 1 || month == 2) {        //※A
 System.out.println("冬です");
} else if (month == 3 || month == 4 || month == 5) {   //※B
 System.out.println("春です");
} else if (month == 6 || month == 7 || month == 8) {   //※C
 System.out.println("夏です");
} else if (month == 9 || month == 10 || month == 11) { //※D
 System.out.println("秋です");
} else {                                                  //※E
 System.out.println("月の値が不正です");
}

問9: 論理積(&&)を用いて値が20未満または65以上の場合に「値は20未満または65以上です。」と表示する。

問10: 「問5」を三項演算子使用して、書いてください。

コード整形について

練習問題が終わったら
コラム「コードの整理」を読んでコードの整理の仕方について学び、これまでのファイルを整えてください。
今後はコード整形も心がけて取り組んでいきましょう!

タイトルとURLをコピーしました