BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース JEP 405: RecordクラスによるJavaのパターンマッチングの拡張

JEP 405: RecordクラスによるJavaのパターンマッチングの拡張

原文(投稿日:2022/05/26)へのリンク

JEP 405 "Record Patterns (Preview)"が、JDK 19のProposed to TargetからTargetedへの昇格を果たした。Project Amberの傘下にあるこのJEPは、レコード値を分解するレコードパターン(record pattern)による言語の拡張を提案する。レコードパターンは型パターン(type pattern)と併用することで、"堅牢で宣言的、かつ構成可能な形式のデータナビゲーションとプロセッシングを可能にする"が、現時点ではまだプレビュー機能に留まっている。

JDK 16で提供されたJEP 394 "Pattern Matching for instanceof"は、instanceof演算子を拡張して、型パターンの指定やパターンマッチングの実行を可能にしたものだ。次の例を見てほしい。

    public void print(Object o) {
        if (o instanceof Double) {
            Double d = (Double) o;
            System.out.println("d = " + d);
        }
    }

パターンマッチングを使えば、上のコードを次のように書き換えることができる。

    public void print(Object o) {
        if (o instanceof Double d) {
            System.out.println("d = " + d);
        }
    }

上のコードでは、実行時のoの値がDoubleのインスタンスであれば、oは型パターンDouble dにマッチする。これによって明示的な型キャストが不要になり、コードがより短く、管理性の高いものになる。

JEP 395 "Records"は、データの透過的キャリアであるRecordクラスを導入することにより、不変(immutable)オブジェクトを簡単に記述できるようにするものだ。次の例を見てほしい。

record Point(int x, int y) { }

ここでは、コンストラクタやアクセッサメソッド、その他toString()hashCode()といったメソッドを明示的に記述する必要がなくなり、コードがクリーンで冗長性が低いものになっている。

レコードクラスのインスタンスがコードブロック内で使用される場合、通常はアクセッサメソッドを使ってデータを取得する。例えば、

    public void printSum(Object o) {
        if (o instanceof Point p) {
            int x = p.x();
            int y = p.y();
            System.out.println(x + y);
        }
    }

上のコードでは、パターン変数pを使ってアクセッサメソッドx()y()を実行することで、xyの値を取得している。それ以外、pは使用されていない。レコードパターンであれば、変数pの必要はなく、

上のコードを次のように書き直すことができる。

public void printSum(Object o) {
   if (o instanceof Point(int x int y)) {
       System.out.println(x + y);
   }
}

同じような方法で、もっと複雑なオブジェクトグラフを分解することも可能だ。以下のコード例を見てほしい。

enum Color {RED, GREEN, BLUE}
record ColoredPoint(Point p, Color color) {}
record Point(int x, int y) {}
record Square(ColoredPoint upperLeft, ColoredPoint lowerRight) {}

レコードパターンを使ったパターンマッチングのシナリオで、左上(upperLeft)のColorPointを表示する必要のある場合は、次のように分解することができる。

public void printUpperLeftColoredPoint(Square s) {
    if (s instanceof Square(ColoredPoint(Point(var x, var y), var color), var leftRight))){
    }
}

上のような分解を使用しないとすれば、コードはもっと冗長なものになる。

さらに型パターンは、JEP 406 "Pattern Matching for switch (Preview)"(JDK 17で提供)、およびJEP 420 "Pattern Matching for switch (Second Preview)"(JDK 18で提供)を通じて、switchのcaseラベルとして使用できるように拡張されている。これらにより、同じような分解をswitch文でも使うことができるようになる。ただし、このJEPは現在も検討中であるため、さまざまな方向に展開され、拡張される可能性がある。興味のある開発者は、メーリングリストを見たり、ディスカッションに参加したりするとよいだろう。

作者について

この記事に星をつける

おすすめ度
スタイル

BT