Java Academy · レッスン

switch のパターン

Sealed 型とパターンを組み合わせます。

レッスン 4/413 ステップ

「switch のパターン」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

switch でパターンを使う

switch は定数にマッチするだけでなく、パターンにもマッチできるようになりました。sealed 型やレコードと組み合わせると、switch で型による振り分けやデータの分解を行い、網羅性も保証できます。

switch の型パターン

各 case に型パターンを指定し、その分岐用の型付き変数を束縛できます。

public class Main {
    static String kind(Object o) {
        return switch (o) {
            case Integer i -> "int " + i;
            case String s -> "string " + s;
            default -> "other";
        };
    }

    public static void main(String[] args) {
        System.out.println(kind(42));
        System.out.println(kind("hi"));
        System.out.println(kind(3.14));
    }
}

sealed 型では default が不要

セレクターが sealed 型で、許可されたすべてのサブタイプを網羅している場合、default がなくても switch は網羅的になります。

public class Main {
    sealed interface Shape permits Circle, Square {}
    record Circle(double r) implements Shape {}
    record Square(double s) implements Shape {}

    static double area(Shape shape) {
        return switch (shape) {
            case Circle c -> Math.PI * c.r() * c.r();
            case Square sq -> sq.s() * sq.s();
        };
    }

    public static void main(String[] args) {
        System.out.printf("%.2f%n", area(new Square(3)));
    }
}

case でレコードパターンを使う

case ではレコードを分解し、コンポーネントを分岐本体から直接利用できます。

public class Main {
    sealed interface Shape permits Circle, Rectangle {}
    record Circle(double r) implements Shape {}
    record Rectangle(double w, double h) implements Shape {}

    static double area(Shape shape) {
        return switch (shape) {
            case Circle(double r) -> Math.PI * r * r;
            case Rectangle(double w, double h) -> w * h;
        };
    }

    public static void main(String[] args) {
        System.out.printf("%.2f%n", area(new Rectangle(2, 5)));
    }
}

when によるガード

when 節を使うと、case にブール値のガードを追加できます。パターンに適合し、かつガードが true の場合にだけ case がマッチします。

public class Main {
    static String size(Object o) {
        return switch (o) {
            case Integer i when i < 0 -> "negative";
            case Integer i when i == 0 -> "zero";
            case Integer i -> "positive";
            default -> "not an int";
        };
    }

    public static void main(String[] args) {
        System.out.println(size(-5));
        System.out.println(size(0));
        System.out.println(size(7));
    }
}

ガードでは順序が重要

ガード付き case は上から下の順に試されます。より具体的なガード付き case は、より広いガードなしの case より前に置く必要があります。そうしないと、広い case に先に取り込まれてしまいます。

null を処理する

null のセレクターを処理するには case null を追加します。追加しない場合、switch は NullPointerException をスローします。case null, default のように組み合わせることもできます。

public class Main {
    static String label(String s) {
        return switch (s) {
            case null -> "missing";
            case "yes" -> "affirmative";
            default -> "other: " + s;
        };
    }

    public static void main(String[] args) {
        System.out.println(label(null));
        System.out.println(label("yes"));
        System.out.println(label("maybe"));
    }
}

switch でネストしたパターンを使う

case ではレコードパターンをネストして、深い構造にマッチし、内側の値に対するガードを1か所で記述できます。

public class Main {
    record Point(int x, int y) {}
    record Line(Point a, Point b) {}

    static String describe(Object o) {
        return switch (o) {
            case Line(Point(var x1, var y1), Point(var x2, var y2)) when x1 == x2 -> "vertical";
            case Line(Point a, Point b) -> "line";
            default -> "other";
        };
    }

    public static void main(String[] args) {
        System.out.println(describe(new Line(new Point(1, 0), new Point(1, 5))));
        System.out.println(describe(new Line(new Point(0, 0), new Point(2, 3))));
    }
}

文と式

パターン switch は式としても文としても使えます。式では -> または yield によって値を生成します。セレクターが sealed 型の場合は、網羅性のルールが適用されます。

Visitor コードを置き換える

sealed 型とパターン switch を組み合わせると、冗長な Visitor パターンや instanceof の連鎖を、閉じたモデルに対する簡潔でコンパイラー検証済みの振り分けに置き換えられます。

完全なインタープリター

sealed 型のモデルとパターン switch を使った式評価器です。

public class Main {
    sealed interface Expr permits Num, Add, Mul {}
    record Num(int value) implements Expr {}
    record Add(Expr left, Expr right) implements Expr {}
    record Mul(Expr left, Expr right) implements Expr {}

    static int eval(Expr e) {
        return switch (e) {
            case Num(int v) -> v;
            case Add(Expr l, Expr r) -> eval(l) + eval(r);
            case Mul(Expr l, Expr r) -> eval(l) * eval(r);
        };
    }

    public static void main(String[] args) {
        Expr e = new Add(new Num(2), new Mul(new Num(3), new Num(4)));
        System.out.println(eval(e));
    }
}

理解度チェック

switch でのパターンの理解度を確認しましょう。

まとめ

switch でのパターンについて学びました。

  • case では型パターンやレコードパターンを使い、データを分解できます。
  • sealed 型のセレクターでは、default なしで網羅的な switch を記述できます。
  • when ガードで case をより絞り込めます。順序も重要です。
  • case null で null を安全に処理できます。
無料で開始

AI チューターと学ぶ Java — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
104
レッスン
374

よくある質問

「switch のパターン」レッスンは無料ですか?

はい。「switch のパターン」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「switch のパターン」で何を学びますか?

Sealed 型とパターンを組み合わせます。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「switch のパターン」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. instanceof のパターンマッチング
  2. Record パターン
  3. ネストした Record パターン
  4. switch のパターン
← Java Academyに戻る