Javaのif文とは、かっこの中の条件式がtrueのときだけ、続くブロックの処理を実行する条件分岐の構文です。 if (条件式) { 処理 } が基本の形で、else で「そうでないとき」、else if で「別の条件のとき」を足していきます。複数の条件は &&(かつ)と ||(または)でつなぎます。

この記事では、if文の書き方をすべて実行結果つきで順番に確かめます。比較演算子・論理演算子の早見表、&& と & の違いがひと目でわかる短絡評価の確認コード、文字列を == で比べて分岐しない例、セミコロンの誤記、nullでのNullPointerException、else ifの並び順による判定漏れまで、つまずきやすい箇所を実際に再現して直し方を示します。最後に、Java 21のswitch式・パターンマッチングとの使い分けも表で整理します。実行環境は OpenJDK 21.0.10 です。

if文の早見表

まずは書き方の全体像です。迷ったらこの表の「書き方」をコピーして、条件式と処理だけ差し替えれば動きます。

やりたいこと 書き方 補足
条件を満たすときだけ実行 if (x > 0) { ... } 条件式は必ずboolean型
満たさないときの処理も書く if (x > 0) { ... } else { ... } どちらか一方が必ず実行される
3つ以上に分ける if (a) { ... } else if (b) { ... } else { ... } 上から順に判定し、最初にtrueになった1つだけ実行
AかつB if (a && b) 左がfalseなら右は評価しない(短絡評価)
AまたはB if (a || b) 左がtrueなら右は評価しない(短絡評価)
Aではない if (!a) trueとfalseを反転
範囲の判定 if (x >= 10 && x <= 20) 10 <= x <= 20 とは書けない
文字列が等しいか if ("yes".equals(s)) == ではなく equals を使う
nullかどうか if (s == null) / if (s != null) nullの判定は == でよい
型の判定と取り出し if (obj instanceof String s) Java 16以降
値を1つ選ぶだけ String r = x > 0 ? "正" : "0以下"; 三項演算子
1つの値で多数に分ける switch (x) { case 1 -> ...; default -> ...; } Java 14以降のswitch式

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Java if文の書き方|else ifと複数条件(&&,||)を解説」

if・else・else ifの基本の書き方

3つの形を1つのコードで確かめる

if文には 「ifだけ」「if-else」「if-else if-else」の3つの形があります。次のコードは3つをまとめたものです。ファイル名を IfBasic.java として保存し、java IfBasic.java で実行できます。

public class IfBasic {
    public static void main(String[] args) {
        int score = 72;

        // 1) if だけ
        if (score >= 60) {
            System.out.println("合格です");
        }

        // 2) if - else
        if (score >= 80) {
            System.out.println("80点以上です");
        } else {
            System.out.println("80点未満です");
        }

        // 3) if - else if - else
        if (score >= 90) {
            System.out.println("評価: A");
        } else if (score >= 70) {
            System.out.println("評価: B");
        } else if (score >= 60) {
            System.out.println("評価: C");
        } else {
            System.out.println("評価: D");
        }
    }
}

実行結果(OpenJDK 21.0.10):

合格です
80点未満です
評価: B

score は72なので、3つ目のif文では score >= 90 がfalse、次の score >= 70 がtrueになり「評価: B」が出力されます。else ifは最初にtrueになったブロックだけを実行し、残りの判定は行いません。 72は score >= 60 も満たしますが、「評価: C」は出力されていない点に注目してください。

構文のルール

部品 ルール
if (条件式) かっこは必須。条件式はboolean型(trueかfalse)になる式だけ書ける
{ ... } 条件がtrueのときに実行するブロック。1文だけなら省略できるが、付けておくと安心
else if (条件式) 何個でも続けられる。elseif や elif ではなく、else と if の間に半角スペース
else 条件式は書かない。どれにも当てはまらないときの受け皿で、最後に1つだけ

流れを図にすると次のようになります。

flowchart TD
    A[開始] --> B{score >= 90}
    B -- true --> C[評価: A]
    B -- false --> D{score >= 70}
    D -- true --> E[評価: B]
    D -- false --> F{score >= 60}
    F -- true --> G[評価: C]
    F -- false --> H[評価: D]
    C --> Z[終了]
    E --> Z
    G --> Z
    H --> Z

ifを並べる書き方とelse ifの違い

else if でつなぐ代わりに if を並べると、動きが変わります。ifを並べると全部の条件を判定し、else ifでつなぐと最初の1つで止まります。

public class IfIf {
    public static void main(String[] args) {
        int score = 95;
        System.out.println("-- if を並べた場合 --");
        if (score >= 60) System.out.println("60点以上");
        if (score >= 70) System.out.println("70点以上");
        if (score >= 90) System.out.println("90点以上");

        System.out.println("-- else if でつないだ場合 --");
        if (score >= 60) System.out.println("60点以上");
        else if (score >= 70) System.out.println("70点以上");
        else if (score >= 90) System.out.println("90点以上");
    }
}

実行結果:

-- if を並べた場合 --
60点以上
70点以上
90点以上
-- else if でつないだ場合 --
60点以上
書き方 判定のされ方 向いている場面
if を並べる すべての条件を毎回判定する。複数のブロックが実行されることがある 互いに独立したチェック(入力項目ごとの確認など)
else if でつなぐ 上から順に判定し、最初にtrueになった1つだけ実行する どれか1つに振り分けたいとき(ランク分け、区分の決定など)

比較演算子の早見表

条件式でいちばんよく使うのが比較演算子です。結果は必ずboolean型(trueかfalse)になります。

演算子 意味 例(a=5, b=8) 結果
== 等しい a == b false
!= 等しくない a != b true
< より小さい a < b true
<= 以下 a <= b true
> より大きい a > b false
>= 以上 a >= b false

表の「結果」は次のコードで確かめた値です。

public class Compare {
    public static void main(String[] args) {
        int a = 5, b = 8;
        System.out.println("a == b : " + (a == b));
        System.out.println("a != b : " + (a != b));
        System.out.println("a <  b : " + (a < b));
        System.out.println("a <= b : " + (a <= b));
        System.out.println("a >  b : " + (a > b));
        System.out.println("a >= b : " + (a >= b));
    }
}

実行結果:

a == b : false
a != b : true
a <  b : true
a <= b : true
a >  b : false
a >= b : false

覚えておきたい点は3つです。

  • 「等しい」は ==(イコール2つ)。=(1つ)は代入です。
  • 「以上」「以下」は >= <= の順で書きます。=> =< とは書けません。
  • == で正しく比べられるのは、int・double・boolean・charなどのプリミティブ型とnullの判定です。Stringなどのオブジェクトの中身を比べるときは equals を使います(後述)。

複数条件の書き方(論理演算子 && || !)

論理演算子の早見表

複数の条件を組み合わせるときは論理演算子を使います。

演算子 読み方 trueになる条件 右側の評価 よく使う場面
&& かつ(AND) 両方がtrue 左がfalseなら評価しない 範囲の判定、nullチェックとの組み合わせ
|| または(OR) どちらかがtrue 左がtrueなら評価しない 複数の値のどれかに一致
! ではない(NOT) 元がfalse ― 条件の反転
& かつ(AND) 両方がtrue 必ず評価する 両方の処理を必ず動かしたいとき(まれ)
| または(OR) どちらかがtrue 必ず評価する 同上(まれ)
^ 排他的論理和(XOR) 片方だけがtrue 必ず評価する 「どちらか一方だけ」の判定

条件分岐では && と || を使うのが基本です。 & と | は整数のビット演算にも使われる演算子で、boolean同士に使うと「短絡評価をしない論理演算」になります。

真理値表もまとめておきます。

A B A && B A || B !A A ^ B
true true true true false false
true false false true false true
false true false true true true
false false false false true false

&& と || と ! を使ったコード

public class Logical {
    public static void main(String[] args) {
        int age = 25;
        boolean member = false;

        // && : 両方 true のときだけ true
        if (age >= 20 && age < 30) {
            System.out.println("20代です");
        }
        // || : どちらかが true なら true
        if (age < 18 || member) {
            System.out.println("割引の対象です");
        } else {
            System.out.println("通常料金です");
        }
        // ! : true と false を反転
        if (!member) {
            System.out.println("会員登録がまだです");
        }
        // && と || を混ぜるときはかっこで意図を示す
        boolean weekend = true;
        if ((age < 18 || member) && weekend) {
            System.out.println("週末割引の対象です");
        } else {
            System.out.println("週末割引の対象外です");
        }
    }
}

実行結果:

20代です
通常料金です
会員登録がまだです
週末割引の対象外です

&& は || より先に計算される

&& と || を1つの式に混ぜると、&& のほうが先に計算されます(掛け算が足し算より先に計算されるのと同じ考え方です)。

public class Priority {
    public static void main(String[] args) {
        boolean a = true, b = false, c = false;
        System.out.println("a || b && c   = " + (a || b && c));
        System.out.println("(a || b) && c = " + ((a || b) && c));
    }
}

実行結果:

a || b && c   = true
(a || b) && c = false

a || b && c は a || (b && c) と同じ意味になり、かっこを付けた (a || b) && c とは結果が変わります。混ぜて使うときは、優先順位を覚えていてもかっこを書くと、読む人にも意図が伝わります。

条件式でよく使う演算子の優先順位は次のとおりです(上ほど先に計算されます)。

順位 演算子 例
1 ! !done
2 < <= > >= instanceof x >= 10
3 == != x == 0
4 & a & b
5 ^ a ^ b
6 | a | b
7 && a && b
8 || a || b
9 ? : a ? 1 : 2
10 = x = 5

短絡評価の動きを実行結果で確かめる

&& と & 、|| と | の違い

短絡評価(ショートサーキット)とは、左側だけで結果が決まったら右側を評価しない動きのことです。「評価しました」と表示するメソッドを使って、右側が呼ばれるかどうかを確かめます。

public class ShortCircuit {
    static boolean check(String name, boolean result) {
        System.out.println("  " + name + " を評価しました -> " + result);
        return result;
    }
    public static void main(String[] args) {
        System.out.println("[1] false && ?");
        System.out.println("  結果: " + (check("左", false) && check("右", true)));
        System.out.println("[2] false & ?");
        System.out.println("  結果: " + (check("左", false) & check("右", true)));
        System.out.println("[3] true || ?");
        System.out.println("  結果: " + (check("左", true) || check("右", false)));
        System.out.println("[4] true | ?");
        System.out.println("  結果: " + (check("左", true) | check("右", false)));
    }
}

実行結果:

[1] false && ?
  左 を評価しました -> false
  結果: false
[2] false & ?
  左 を評価しました -> false
  右 を評価しました -> true
  結果: false
[3] true || ?
  左 を評価しました -> true
  結果: true
[4] true | ?
  左 を評価しました -> true
  右 を評価しました -> false
  結果: true

[1]と[3]では「右 を評価しました」が表示されていません。&& は左がfalseの時点で、|| は左がtrueの時点で結果が決まるため、右側のメソッドは呼ばれません。 一方、[2]と[4]の & | は結果が同じでも右側を必ず呼びます。

式 左の値 右を評価するか 結果
左 && 右 false しない false
左 && 右 true する 右の値
左 || 右 true しない true
左 || 右 false する 右の値
左 & 右 どちらでも 必ずする 両方trueならtrue
左 | 右 どちらでも 必ずする どちらかtrueならtrue

短絡評価が役立つ場面:nullチェックと組み合わせる

短絡評価は、「先にnullでないことを確かめてから、メソッドを呼ぶ」 という書き方を1行で安全に書くために欠かせません。

public class ShortNull {
    public static void main(String[] args) {
        String s = null;
        // && は左が false なら右を評価しないので安全
        if (s != null && s.length() > 0) {
            System.out.println("文字があります");
        } else {
            System.out.println("null または空です");
        }
        // & は右も必ず評価するので s.length() で例外になる
        if (s != null & s.length() > 0) {
            System.out.println("文字があります");
        }
    }
}

実行結果:

null または空です
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "<local1>" is null
    at ShortNull.main(ShortNull.java:11)

1つ目の && は、s != null がfalseになった時点で判定を終えるため、s.length() は呼ばれません。2つ目の & は右側も評価するので、nullに対して length() を呼んで例外になりました。nullチェックは必ず左側に書き、&& でつなぐのがポイントです。順番を逆にして s.length() > 0 && s != null と書くと、先に length() が呼ばれて同じ例外になります。

なお、メッセージ中の "<local1>" は、java ファイル名.java で直接実行したときの表示です。javac -g でデバッグ情報を付けてコンパイルすると because "s" is null のように変数名で表示されます(後述のNullNpe.javaで "status" と表示されることを確認しました)。

文字列の比較はequalsで書く

== で比べると分岐しない例

初心者がもっともつまずきやすいのが、文字列の比較です。Stringを == で比べると「同じオブジェクトかどうか」を調べるため、中身が同じでもfalseになることがあります。

public class StrCompare {
    public static void main(String[] args) {
        String input = new String("yes");   // 入力や読み込みで得た文字列を想定

        if (input == "yes") {
            System.out.println("== : 一致しました");
        } else {
            System.out.println("== : 一致しません");
        }

        if (input.equals("yes")) {
            System.out.println("equals : 一致しました");
        } else {
            System.out.println("equals : 一致しません");
        }

        // 大文字・小文字を区別しない
        System.out.println("equalsIgnoreCase : " + "YES".equalsIgnoreCase(input));
    }
}

実行結果:

== : 一致しません
equals : 一致しました
equalsIgnoreCase : true

input の中身は "yes" ですが、== では「一致しません」になりました。Scannerでキーボードから読んだ文字列や、ファイルから読み込んだ文字列でも同じことが起きます。コンパイルエラーにも例外にもならず、ただifの中に入らないだけなので、原因に気づきにくいのが特徴です。

比べたいもの 書き方 備考
int・long・double・char・boolean a == b プリミティブ型は値で比べる
String a.equals(b) 中身(文字の並び)で比べる
大文字小文字を区別しないString a.equalsIgnoreCase(b) "YES" と "yes" を同じとみなす
nullかどうか a == null nullの判定は ==
Integerなどのラッパー型 a.equals(b) == は後述のとおり値によって結果が変わる
enum a == b enumは == で比べられる

Integerやdoubleの比較で気をつけること

ラッパー型のIntegerと、小数のdoubleにも比較の注意点があります。

public class IntegerEq {
    public static void main(String[] args) {
        Integer a = 127, b = 127;
        Integer c = 1000, d = 1000;
        System.out.println("127 == 127   : " + (a == b));
        System.out.println("1000 == 1000 : " + (c == d));
        System.out.println("1000 equals  : " + c.equals(d));
        double e = 0.1 + 0.2;
        System.out.println("0.1 + 0.2 == 0.3 : " + (e == 0.3));
        System.out.println("差が小さいか     : " + (Math.abs(e - 0.3) < 1e-9));
    }
}

実行結果:

127 == 127   : true
1000 == 1000 : false
1000 equals  : true
0.1 + 0.2 == 0.3 : false
差が小さいか     : true
  • Integer同士の == は、-128〜127の範囲ではtrue、それ以外ではfalseになることがあります(小さい値はJavaが同じオブジェクトを使い回すためです)。Integer同士は equals で比べるか、int に変換してから比べます。
  • doubleの計算結果を == で比べると、わずかな誤差でfalseになることがあります。 「差が十分小さいか」で判定するか、BigDecimalを使います。

初心者がつまずくエラーと直し方

ここからは、実際にエラーや想定外の動きを再現し、直し方を示します。

つまずき早見表

症状 原因 直し方
条件に関係なく処理が実行される if (...) の直後にセミコロン セミコロンを消す
文字列が同じなのにifに入らない == で文字列を比べている equals を使う
NullPointerException nullの変数に対してメソッドを呼んだ "定数".equals(変数) や先にnullチェック
incompatible types: int cannot be converted to boolean == を = と書いた == に直す
bad operand types for binary operator '<=' 10 <= x <= 20 と書いた x >= 10 && x <= 20 に分ける
2行目だけ常に実行される 中かっこを省略した { } を付ける
いつも最初の評価になる else ifの並び順 厳しい条件から先に書く

セミコロンを付けてしまう

public class Semicolon {
    public static void main(String[] args) {
        int stock = 0;
        if (stock > 0); {
            System.out.println("在庫があります");
        }
    }
}

実行結果:

在庫があります

stock は0なのに「在庫があります」と表示されました。if (stock > 0); のセミコロンが「何もしない文」として扱われ、if文がそこで終わっているためです。後ろの { ... } はifとは関係のないただのブロックになり、必ず実行されます。

このコードはコンパイルエラーにならないため見つけにくいのですが、javac -Xlint:all を付けると警告が出ます。

Semicolon.java:4: warning: [empty] empty statement after if
        if (stock > 0); {
                      ^
1 warning

直した後のコードです。

public class SemicolonFixed {
    public static void main(String[] args) {
        int stock = 0;
        if (stock > 0) {
            System.out.println("在庫があります");
        } else {
            System.out.println("在庫がありません");
        }
    }
}

実行結果:

在庫がありません

nullの変数でNullPointerExceptionになる

public class NullNpe {
    public static void main(String[] args) {
        String status = null;
        if (status.equals("done")) {
            System.out.println("完了です");
        }
    }
}

実行結果(javac -g NullNpe.java でコンパイルして実行):

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "status" is null
    at NullNpe.main(NullNpe.java:4)

メッセージは「status がnullなので String.equals(Object) を呼べません」という意味です。nullは「何も指していない」状態なので、メソッドを呼ぶことができません。 直し方は3つあります。

import java.util.Objects;

public class NullFixed {
    public static void main(String[] args) {
        String status = null;

        // 直し方1: 定数側から equals を呼ぶ
        if ("done".equals(status)) {
            System.out.println("1: 完了です");
        } else {
            System.out.println("1: 完了ではありません");
        }
        // 直し方2: Objects.equals はどちらが null でも動く
        if (Objects.equals(status, "done")) {
            System.out.println("2: 完了です");
        } else {
            System.out.println("2: 完了ではありません");
        }
        // 直し方3: 先に null を確かめる(&& の短絡評価)
        if (status != null && status.equals("done")) {
            System.out.println("3: 完了です");
        } else {
            System.out.println("3: 完了ではありません");
        }
    }
}

実行結果:

1: 完了ではありません
2: 完了ではありません
3: 完了ではありません
直し方 書き方 向いている場面
定数側から呼ぶ "done".equals(status) 片方が決まった文字列のとき。いちばん短く書ける
Objects.equals Objects.equals(a, b) 両方が変数で、どちらもnullの可能性があるとき
先にnullチェック status != null && status.equals("done") nullのときに別の処理も書きたいとき

== を = と書いてしまう

public class Assign {
    public static void main(String[] args) {
        int count = 3;
        if (count = 5) {
            System.out.println("5です");
        }
    }
}

実行結果(コンパイルエラー):

Assign.java:4: error: incompatible types: int cannot be converted to boolean
        if (count = 5) {
                  ^
1 error
error: compilation failed

count = 5 は代入で、式の値はint型の5になります。Javaのif文はboolean型しか受け付けないので、コンパイルの時点で気づけるようになっています。== に直せば解決です。

ただし、変数がboolean型のときは = でもコンパイルが通ります。

public class AssignBool {
    public static void main(String[] args) {
        boolean done = false;
        if (done = true) {
            System.out.println("= : 完了と判定されました");
        }
        done = false;
        if (done == true) {
            System.out.println("== : 完了と判定されました");
        } else {
            System.out.println("== : 未完了と判定されました");
        }
        if (done) {
            System.out.println("done : 完了");
        } else {
            System.out.println("done : 未完了(この書き方がおすすめ)");
        }
    }
}

実行結果:

= : 完了と判定されました
== : 未完了と判定されました
done : 未完了(この書き方がおすすめ)

if (done = true) は「doneにtrueを代入し、その値で判定する」という意味になり、元の値に関係なく必ずtrueになります。boolean型の変数は if (done)、否定は if (!done) と書くと、= と == を取り違える余地がなくなります。

範囲を 10 <= x <= 20 と書いてしまう

public class Range {
    public static void main(String[] args) {
        int x = 15;
        if (10 <= x <= 20) {
            System.out.println("範囲内");
        }
    }
}

実行結果(コンパイルエラー):

Range.java:4: error: bad operand types for binary operator '<='
        if (10 <= x <= 20) {
                    ^
  first type:  boolean
  second type: int
1 error
error: compilation failed

10 <= x が先に計算されてboolean型になり、そのbooleanと20を <= で比べようとしてエラーになります。範囲は2つの比較に分けて && でつなぎます。

if (x >= 10 && x <= 20) {
    System.out.println("範囲内");
}

「範囲の外」を判定したいときは x < 10 || x > 20 と書きます。

中かっこを省略して2行書いてしまう

public class NoBrace {
    public static void main(String[] args) {
        int stock = 0;
        if (stock > 0)
            System.out.println("在庫があります");
            System.out.println("出荷します");
    }
}

実行結果:

出荷します

在庫が0なのに「出荷します」が表示されました。中かっこを省略すると、ifの対象になるのは直後の1文だけです。インデントをそろえても、2行目はif文の外にあります。処理が1行のときも { } を付けておくと、後から行を足したときにこの問題が起きません。

else ifの並び順で判定が漏れる

条件の順番を入れ替えただけで結果が変わる

else ifは上から順に判定します。そのため、ゆるい条件を先に書くと、後ろの条件に届かなくなります。

public class Order {
    static String before(int score) {
        if (score >= 60) {
            return "C";
        } else if (score >= 70) {
            return "B";
        } else if (score >= 90) {
            return "A";
        } else {
            return "D";
        }
    }
    static String after(int score) {
        if (score >= 90) {
            return "A";
        } else if (score >= 70) {
            return "B";
        } else if (score >= 60) {
            return "C";
        } else {
            return "D";
        }
    }
    public static void main(String[] args) {
        int[] scores = {95, 75, 65, 40};
        for (int s : scores) {
            System.out.println(s + "点 -> 直す前: " + before(s) + " / 直した後: " + after(s));
        }
    }
}

実行結果:

95点 -> 直す前: C / 直した後: A
75点 -> 直す前: C / 直した後: B
65点 -> 直す前: C / 直した後: C
40点 -> 直す前: D / 直した後: D

直す前のコードでは、95点も75点も最初の score >= 60 に当てはまってしまい、「A」「B」の判定に届きません。コンパイルエラーも例外も出ないため、テストで値を変えて確かめるまで気づきにくいところです。

並び順を決めるルール

ルール 説明 例
厳しい条件から先に書く 当てはまる値が少ない条件を上に置く >= 90 → >= 70 → >= 60
大きい順か小さい順にそろえる 順番が混ざると読み手が追いにくい < 10 → < 100 → < 1000
特別な値は最初に判定する null・0・空文字などは先に除外する if (s == null) を先頭に
最後にelseを置く 想定外の値の受け皿を用意する else { return "D"; }
境界の値でテストする 境目とその前後の値で確かめる 59・60・69・70・89・90

条件同士が重ならないように書く方法もあります。score >= 70 && score < 90 のように上限も書けば順番に左右されなくなりますが、条件が長くなり、境界の書き間違いも増えます。「厳しい条件から順に並べる」ほうが短く、読みやすく書けます。

ネストを浅くする早期リターン

if文の中にif文を入れることを「ネスト(入れ子)」と呼びます。ネストが深くなると読みにくくなるため、条件を満たさない場合を先に return で抜ける書き方(早期リターン) がよく使われます。

public class EarlyReturn {
    // ネストが深い書き方
    static String nested(String name, int stock, int qty) {
        if (name != null) {
            if (stock > 0) {
                if (qty <= stock) {
                    return "注文を受け付けました";
                } else {
                    return "在庫が足りません";
                }
            } else {
                return "在庫がありません";
            }
        } else {
            return "商品名がありません";
        }
    }
    // 早期リターンで平らにした書き方
    static String flat(String name, int stock, int qty) {
        if (name == null) return "商品名がありません";
        if (stock <= 0)   return "在庫がありません";
        if (qty > stock)  return "在庫が足りません";
        return "注文を受け付けました";
    }
    public static void main(String[] args) {
        System.out.println(nested("ノート", 5, 2) + " / " + flat("ノート", 5, 2));
        System.out.println(nested("ノート", 5, 9) + " / " + flat("ノート", 5, 9));
        System.out.println(nested("ノート", 0, 1) + " / " + flat("ノート", 0, 1));
        System.out.println(nested(null, 5, 1) + " / " + flat(null, 5, 1));
    }
}

実行結果:

注文を受け付けました / 注文を受け付けました
在庫が足りません / 在庫が足りません
在庫がありません / 在庫がありません
商品名がありません / 商品名がありません

2つのメソッドは同じ結果を返しますが、flat のほうは上から順に読むだけで条件がわかります。ネストが3段を超えてきたら、早期リターンや && での結合、メソッドへの切り出しを検討するとよいでしょう。

三項演算子・switch式・パターンマッチングとの使い分け

三項演算子:値を1つ選ぶだけのとき

三項演算子は 条件 ? trueのときの値 : falseのときの値 の形で、if-elseを1行で書けます。

public class Ternary {
    public static void main(String[] args) {
        int stock = 3;
        // if - else
        String label;
        if (stock > 0) {
            label = "在庫あり";
        } else {
            label = "在庫なし";
        }
        // 三項演算子
        String label2 = stock > 0 ? "在庫あり" : "在庫なし";
        System.out.println(label + " / " + label2);
    }
}

実行結果:

在庫あり / 在庫あり

値を1つ選んで変数に入れるだけなら三項演算子が簡潔です。三項演算子を2段、3段と重ねると読みにくくなるので、そのときはif文かswitch式に戻します。

switch式とパターンマッチング(Java 21)

1つの値を多数の候補と比べるなら、switchのほうが見通しよく書けます。Java 14以降のswitch式は -> で書け、値を返せます。Java 21ではパターンマッチングが正式機能になり、型による分岐や case null も書けるようになりました。

public class SwitchDemo {
    // if - else if で書いた場合
    static String byIf(String size) {
        if ("S".equals(size)) {
            return "小";
        } else if ("M".equals(size)) {
            return "中";
        } else if ("L".equals(size) || "XL".equals(size)) {
            return "大";
        } else {
            return "不明";
        }
    }
    // switch 式(Java 14 以降)
    static String bySwitch(String size) {
        return switch (size) {
            case "S" -> "小";
            case "M" -> "中";
            case "L", "XL" -> "大";
            default -> "不明";
        };
    }
    // パターンマッチング(Java 21 以降)
    static String describe(Object o) {
        return switch (o) {
            case null -> "null です";
            case Integer i when i >= 100 -> "大きな整数 " + i;
            case Integer i -> "整数 " + i;
            case String s -> "文字列 " + s + "(" + s.length() + "文字)";
            default -> "その他 " + o;
        };
    }
    public static void main(String[] args) {
        for (String s : new String[]{"S", "M", "XL", "Z"}) {
            System.out.println(s + " -> if: " + byIf(s) + " / switch: " + bySwitch(s));
        }
        System.out.println(describe(5));
        System.out.println(describe(250));
        System.out.println(describe("task"));
        System.out.println(describe(null));
        System.out.println(describe(3.14));
    }
}

実行結果(OpenJDK 21.0.10):

S -> if: 小 / switch: 小
M -> if: 中 / switch: 中
XL -> if: 大 / switch: 大
Z -> if: 不明 / switch: 不明
整数 5
大きな整数 250
文字列 task(4文字)
null です
その他 3.14

case Integer i when i >= 100 の when は、型に加えて条件を付ける書き方です。ここでもelse ifと同じく上から順に判定されるので、条件付きの case を先に書きます。なお、case null を書いていないswitchにnullを渡すとNullPointerExceptionになります。

if文の中でも、Java 16以降は instanceof で型の判定と変数への取り出しを同時に書けます。

public class InstanceOf {
    public static void main(String[] args) {
        Object value = "hello";
        // Java 16 以降: 型の判定と変数への代入を1行で
        if (value instanceof String s && s.length() >= 3) {
            System.out.println("3文字以上の文字列: " + s.toUpperCase());
        }
    }
}

実行結果:

3文字以上の文字列: HELLO

使い分けの判断表

状況 おすすめ 理由
条件が1〜2個 if / if-else もっとも素直に読める
範囲で分ける(60以上、70以上…) if-else if 大小比較を順に並べられる
複数の変数を組み合わせた条件 if + && || switchは1つの値が対象
1つの値を多数の定数と比べる switch式 候補が縦に並び、抜けを見つけやすい
enumの値で分ける switch式 すべての値を書けばdefaultが不要になり、値を追加したときにコンパイルで気づける
型によって処理を分ける switchのパターンマッチング(Java 21) 型の判定と変数への取り出しを同時に書ける
値を1つ選んで代入するだけ 三項演算子 1行で書ける
nullかもしれない値 ifで先にnullを除外、または case null 例外を避けられる

バージョンごとに使える書き方も整理しておきます。

書き方 使えるバージョン
if / else if / else、三項演算子、従来のswitch文 すべてのバージョン
Stringを使ったswitch Java 7以降
switch式(->、値を返す) Java 14以降
instanceof のパターンマッチング Java 16以降
switchのパターンマッチング(型・when・case null) Java 21以降

if文を書くときのチェックリスト

確認すること チェック
if (...) の直後にセミコロンを付けていない □
処理が1行でも { } を付けている □
文字列は equals で比べている □
nullの可能性がある変数は、先にnullチェックするか "定数".equals(変数) にしている □
「等しい」は ==、boolean変数は if (done) と書いている □
範囲は x >= 10 && x <= 20 と2つに分けている □
&& と || を混ぜるときはかっこを付けている □
else ifは厳しい条件から順に並べている □
最後に else を置いて、想定外の値を受けている □
境界の値(ちょうど60、59、61など)でテストした □

よくある質問

Q. else ifはいくつまで書けますか? A. 数に上限はありません。ただし、5個、6個と続くときは、switch式に置き換えられないか、判定をメソッドに切り出せないかを考えると読みやすくなります。1つの値を定数と比べているだけならswitch式が向いています。

Q. && と & はどちらを使えばよいですか? A. 条件分岐では && と || を使います。左側だけで結果が決まれば右側を評価しないため、s != null && s.length() > 0 のようなnullチェックとの組み合わせが安全に書けます。& と | は右側も必ず評価するので、本記事の実行結果のとおりnullで例外になることがあります。

Q. 文字列を == で比べてもtrueになることがあるのはなぜですか? A. "yes" == "yes" のようにソースコードに直接書いた文字列同士は、Javaが同じオブジェクトを共有するためtrueになります。入力や読み込み、new String(...)、文字列の連結などで作られた文字列は別のオブジェクトになるため、中身が同じでもfalseになります。結果が状況によって変わるので、文字列は常に equals で比べるのが確実です。

Q. elseは必ず書く必要がありますか? A. 必須ではありません。条件を満たすときだけ処理をしたい場合は if だけで十分です。else ifで振り分けるときは、想定していない値が来たときの受け皿として else を置いておくと、原因を追いやすくなります。

まとめ

  • if文は if (条件式) { 処理 } が基本。else で「そうでないとき」、else if で別の条件を足す
  • else ifは上から順に判定し、最初にtrueになった1つだけ実行する。厳しい条件から先に並べる
  • 複数条件は &&(かつ)と ||(または)。&& のほうが先に計算されるので、混ぜるときはかっこを付ける
  • 短絡評価により、&& は左がfalseなら、|| は左がtrueなら右を評価しない。nullチェックは左側に書く
  • 文字列は == ではなく equals で比べる。nullの可能性があれば "定数".equals(変数) か Objects.equals
  • if (...) の直後のセミコロン、中かっこの省略、= と == の取り違えは、エラーにならず動きだけ変わることがある
  • 1つの値を多数に分けるならswitch式、型で分けるならJava 21のパターンマッチングが読みやすい

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Java if文の書き方|else ifと複数条件(&&,||)を解説」

株式会社RJCでは、Javaのif文や条件分岐の書き方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?