BT

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

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース JDK 16で確定された Records と Instanceof のパターンマッチング

JDK 16で確定された Records と Instanceof のパターンマッチング

原文(投稿日:2020/08/12)へのリンク

Records の最終リリースと新しい instanceof のパターンマッチング機能は JDK 16 で予定されている。これらの新機能により、ボイラプレートコードが削減され、エラーが発生しにくいコードになる。

どちらの機能もすでに JDK 1415 でプレビューとして公開されていた。これらは若干改良されており、2021 年 3 月にリリースが予定されている JDK 16 で利用できるようになっている。すべてが計画通りにいけば、2021 年 9 月に予定されている次期長期サポート版である JDK 17 で新機能が利用できる。

Records

Records は名前付きタプルの Java 版であり、基本的には順番に並んだ要素の入れ物だ。Records を使う場合、API と表現を切り離すことができなくなった。これらは Records 宣言から派生したものだ。

この機能の主な効果の一つは、ボイラプレートコードを削減できることだ。 これまでは、getter、setter、equalstoStringhashCodeのようなメソッドやコンストラクタを持つクラスは、手書きで書かなければならなかった。いくつかのプロジェクトでは、Lombok のようなライブラリを使用して、ボイラプレートコードの量を減らしていた。残念ながら、Lombok は IDE プラグインの形で余分なサポートを必要としている。新しい Records 機能を使えば、この処理が簡単になり、エラーが出にくくなるはずだ。

開始するには、Records を定義する必要がある。

record Name(String firstName, String lastName){}

Records は、別のファイルで宣言することも、別のクラスの一部として宣言することもできる。Records には多くのユースケースがある。メソッドから複数の値を返したり、マップ内の複合キーとして使用したり、単にデータオブジェクトとして使用できる。

通常のクラスが定義されている場合、暗黙のうちにデフォルトのコンストラクタが追加される。Records は似たような挙動をしており、暗黙のうちに多くのメンバーが含まれる。

  • Records のすべてのコンポーネントのプライベートフィールド。
  • Records のすべてのコンポーネントのためのパブリック・アクセサ・メソッド。
  • Records のすべてのコンポーネントの引数を持つコンストラクタ。このコンストラクタはカノニカルコンストラクタ(canonical constructor)と名付けられている。
  • equalstoString、および hashCode メソッドを実装。

先ほど定義した Records にはカスタムコードは含まれていない。しかし、明示的なメソッドを定義することは可能だ。暗黙のうちに追加された様々なメソッドやカノニカルコンストラクタを明示的に宣言することも可能だ。例えば、カスタムの toString メソッドを作成できる。

JDK 14 では、カノニカルコンストラクタは public である必要があった。JDK 15 以降では、暗黙のカノニカルコンストラクタは Records クラスと同じアクセス修飾子を取得する。明示的なカノニカルコンストラクタを定義する場合、アクセス修飾子は少なくとも Records クラスと同じアクセスを提供しなければならない。

変更の一環として、@Override アノテーションも変更された。Records 内の明示的なアクセサメソッドのアノテーションに使用できるようになった。

Brian Goetz 氏が書いた Java 14 Feature Spotlight:Records では、Records の詳細と例を紹介している。

instanceof のパターンマッチング

オブジェクトが特定の型であるかどうかを検証し、それを使用することは、常に 2 段階の手順だった。最初に、引数が正しい型であるかどうかを確認するために instanceof が使用され、その後、オブジェクトがその特定の型にキャストされた。その後、以下の customer の pay() メソッドのように、オブジェクト固有のメソッドを呼び出せる。

if (person instanceof Customer) {
    Customer customer = (Customer) person;
    customer.pay();
}

新しいパターンマッチング機能で、同じ機能をよりコンパクトに書けるようになった。この場合、customer はいわゆるパターン変数と呼ばれる。パターン変数が正常に一致したときに、パターン変数はスコープに入る。

if (person instanceof Customer customer) {
    customer.pay();
}

現在、パターンマッチング機能は主にボイラプレートコードを削減している。ただし、この機能は将来の Java バージョンでは Switch 式に使用される予定だ。 

パターン変数はフィールドの可視性に影響を及ぼせる。例えば、customer パターン変数は、customer フィールドを不可視にする。

//  customer フィールドの範囲
if (person instanceof Customer customer) {
    // customer はパターン変数を参照
} else {
    // customer はそのフィールドを参照
}

パターンマッチングの instanceof 式を他の式と組み合わせることで、以下の equals メソッドのようなよりコンパクトなメソッドを書ける。

@Override
public boolean equals(Object o) {
    return o instanceof Customer other &&
            name.equals(other.name);
}

古い方法は以下:

@Override
public boolean equals(Object o) {
    if (o instanceof Customer) {
        Customer other = (Customer) o;
        if (name.equals(other.name)) {
            return true;
        }
    }
    return false;
}

この記事に星をつける

おすすめ度
スタイル

BT