S-JIS[2024-09-22/2025-03-19] 変更履歴

プリミティブ型のパターンマッチ(Java23〜24)

Java23のプリミティブ型のパターンマッチ(プレビュー版)について。


概要

2024/9/17にリリースされたJava23で、プレビュー版として プリミティブ型でパターンマッチが出来るようになった。


プリミティブ型のパターンマッチはJava23〜24ではプレビュー版の機能なので、この機能を使いたい場合はコンパイル時にjavacコマンドに--enable-previewを付ける必要があり、
また、実行時にjavaコマンドに--enable-previewを付ける必要がある。
JShellで試す場合もjshellコマンドに--enable-previewを付ける。

> javac --enable-preview --release 23 Example.java
> java --enable-preview Example
> java --enable-preview --source 23 Example.java

instanceofの例

(Java16以降の)instanceofでは「if (値 instanceof 型 変数)」のように書くことが出来るが、プリミティブ型も使えるようになった。

    int n = 127;
    if (n instanceof byte b) {
        System.out.println(b);
    } else {
        System.out.println("unmatch");
    }

「n instanceof byte」の場合、nがbyteの範囲に収まっているとtrueになる。
-128や127はbyteの範囲内なのでマッチするが、-129や128はbyteの範囲外なのでマッチしない。


普通、「obj instanceof T」は「objがTにキャスト可能かどうか」「objをTとして扱えるかどうか」を判定するのに使う。

それと同じく、「n instanceof byte」は「byteにキャスト可能か」「byteとして扱えるか」と解釈することも出来そうだ。
この場合、nがbyteの範囲に入っているということを意味する。

例えば、byteの範囲外である128をbyteに強制的にキャスト(「(byte)128」)すると-128になってしまう。
128と-128は違う値なので、これは確かに「byteとして扱えない」と言えるような気がする。


ちなみに、「n instanceof byte」は、コンパイルするとExactConversionsSupport.isIntToByteExact()の呼び出しになっている。

ExactConversionsSupportはJava23で新設されたクラスで、isIntToByteExactメソッドは以下のようになっている。

    public static boolean isIntToByteExact(int n) {
        return n == (int)(byte)n;
    }

switchの例

(Java21以降の)switchでは「case Integer i」のように書くことが出来るが、プリミティブ型も指定できるようになった。

    long value = 128;
    String type = switch (value) {
        case byte _  -> "byte";
        case short _ -> "short";
        case int _   -> "int";
        case long _  -> "long";
    };
    System.out.printf("%d in %s%n", value, type);

「case 型 変数」なので変数は省略できないが、変数を使わない場合はアンダースコア「_」にしておけばいい。

「case byte」は、byteの範囲に収まっているとき(-128〜127のとき)にマッチする。


    for (int i = 0; i < 10; i++) {
        String s = switch (i) {
            case 0 -> "nothing";
            case 1 -> "one";
            case 2 -> "two";
            case 3 -> "three";
            case int n -> "many (%d)".formatted(n);
        };
        System.out.println(s);
    }

int iに対して「switch(i)」の場合、「case int n」は全ての値とマッチする。
意味合いは「default」と同じだが、defaultとは違い、そのときの値を変数で受け取ることが出来る。


    for (int i = 1; i <= 20; i++) {
        String s = switch (i) {
            case int n when n % 15 == 0 -> "FizzBuzz";
            case int n when n %  3 == 0 -> "Fizz";
            case int n when n %  5 == 0 -> "Buzz";
            case int n                  -> Integer.toString(n);
        };
        System.out.println(s);
    }

プレビュー機能へ戻る / Java目次へ戻る / 新機能へ戻る / 技術メモへ戻る
メールの送信先:ひしだま