型パターン
型パターンは、型と1つのパターン変数で構成されます。値がパターンに出現する型のインスタンスであるかどうかをテストするために使用されます。
参照型を持つ型パターン
型パターンのパターン変数は、任意の参照型にできます。
次のswitch
文は、セレクタ式obj
を、クラス型、列挙型、レコード型およびint[]
配列型を含む型パターンと一致させます:
record Point(int x, int y) { }
enum Color { RED, GREEN, BLUE; }
//...
static void typeTester(Object obj) {
switch (obj) {
case null -> System.out.println("null");
case String s -> System.out.println("String");
case Color c -> System.out.println("Color with " + c.values().length + " values");
case Point p -> System.out.println("Record class: " + p.toString());
case int[] ia -> System.out.println("Array of int values of length" + ia.length);
default -> System.out.println("Something else");
}
}
プリミティブ型を持つ型パターン
参照型のかわりにプリミティブ型を型パターンに指定できます。
ノート:
型パターンでのプリミティブ型はプレビュー機能です。プレビュー機能は、設計、仕様および実装が完了したが、永続的でない機能です。プレビュー機能は、将来のJava SEリリースで、異なる形式で存在することもあれば、まったく存在しないこともあります。プレビュー機能が含まれているコードをコンパイルして実行するには、追加のコマンド行オプションを指定する必要があります。『Preview Language and VM Features』を参照してください。詳細は、JEP 455: パターン、instanceofおよびswitchでのプリミティブ型(プレビュー)を参照してください。
次の例では、型パターンを使用して、値がfloat
、double
またはint
であるかどうかをテストします:
float v = 1000.01f;
if (v instanceof float f) System.out.println("float value: " + f);
if (v instanceof double d) System.out.println("double value: " + d);
if (v instanceof int i) System.out.println("int value: " + i);
次のような出力が表示されます:
float value: 1000.01
double value: 1000.010009765625
この例で変換されたdouble
値が元のfloat
値と異なる理由については、DoubleのJavaDoc APIドキュメントの10進数と2進数の間の変換の問題の項を参照してください。
ヒント:
値のキャスト時に型の安全性を確保するには、プリミティブによるパターン・マッチングを使用するのが特に有効です。詳細は、「instanceofおよびswitchによる安全なキャスト」を参照してください。次のswitch
式のcaseラベルは、float
を含む型パターンを使用しています:
String floatToRating(float rating) {
return switch(rating) {
case 0f -> "0 stars";
case 2.5f -> "Average";
case 5f -> "Best";
case float f -> "Invalid rating: " + f;
};
}
パラメータ化された型を持つ型パターン
「instanceofおよびswitchによる安全なキャスト」で説明されているように、instanceof
演算子を使用して、右オペランドの型を左オペランドの型にキャストできるかどうかをテストできます。これは、右オペランドが1つ以上のパラメータ化された型を含む型パターンである場合にも当てはまります。ただし、型消去(Javaチュートリアルの型消去を参照)のため、パラメータ化された型の情報は実行時に存在しません。したがって、ランタイムがパラメータ化された型を含む型間のキャストを完全に検証することはできません。コンパイラは、このような状況に対して警告またはエラーを生成します。ただし、パラメータ化された型を含むinstanceof
オペランド間のキャストを完全に検証できない場合、コンパイラはエラーを生成します。
ListをList<String>にキャストしようとする次の例について考えてみます:
List myList = null;
List<String> stringList = (List<String>) myList;
-Xlint:unchecked
オプションが指定されていると、コンパイラは次の警告を生成します:
warning: [unchecked] unchecked cast
List<String> stringList = (List<String>) myList;
^
required: List<String>
found: List
instanceof
演算子によって、myList
(List)の型がList<String>かどうかをテストする次の例について考えてみます:
List myList = null;
if (myList instanceof List<String> sl) {
System.out.println("myList is a List<String>, size " + sl.size());
}
コンパイラは、2番目のinstanceof
式に対してエラーを生成します:
error: List cannot be safely cast to List<String>
if (myList instanceof List<String> sl) {
^
次に、パラメータ化された型を持つ型パターンを含むinstanceof
式の例をさらに示します。
public class Box<T> {
private T t;
public Box() { }
public Box(T t) { this.t = t; }
public void set(T t) { this.t = t; }
public T get() { return t; }
}
public class Shoebox<T> extends Box<T> {
public Shoebox(T t) { super(t); }
}
// ...
Shoebox<String> sb = new Shoebox<>("a pair of new shoes");
if (sb instanceof Box<String> s) {
System.out.println("Box<String> contains: " + s.get());
}
if (sb instanceof Shoebox<String> s) {
System.out.println("Shoebox<String> contains: " + s.get());
}
if (sb instanceof Shoebox<?> s) {
System.out.println("Shoebox<?> contains: " + s.get());
}
if (sb instanceof Shoebox<Object> s) {
// error: incompatible types: Shoebox<String> cannot be
// converted to Shoebox<Object>
System.out.println("Shoebox<Object> contains: " + s.get());
}
次の式はtrue
を返します。instanceof
パターン一致演算子の両側の型パラメータは同じです:
sb instanceof Box<String> s
sb instanceof Shoebox<String> s
式sb instanceof Shoebox<?> s
は、true
を返します。ワイルドカード型(?
)は、すべての型に一致します。
ただし、String
がObject
のサブタイプであっても、コンパイラがShoebox<Object>
をShoebox<String>
にキャストできるかどうかを実行時に完全に検証することはできません。型消去のため、このパラメータ化された型の情報は実行時に存在しません。その結果、コンパイラは次の式に対してエラーを生成します:
sb instanceof Shoebox<Object> s
ノート:
前の例では、instanceof
をパターン一致演算子として使用しています。instanceof
を型比較演算子として使用しても、パラメータ化された型と型消去に関する同じ問題が依然として当てはまります。たとえば、コンパイラは次の式に対してエラーを生成します:sb instanceof Shoebox<Object>