8 無名変数およびパターン
無名変数は、初期化はできるが使用できない変数です。無名パターンは、レコード・パターンのパターン・リストに出現することがあり、対応するレコード・コンポーネントと常に一致します。これらは型パターンのかわりに使用できます。後続のコードでは必要のないパターン変数の型と名前を記述する必要がなくなります。両方ともアンダースコア文字(_
)で示します。
無名変数とパターンの背景情報は、JEP 456を参照してください。
無名変数
アンダースコア・キーワード(_
)は、宣言の値が不要な場合の宣言でローカル変数、例外またはラムダ・パラメータの名前として使用できます。これは無名変数と呼ばれ、宣言されている変数を表しますが、使用可能な名前はありません。
無名変数は、文の副次的効果が結果よりも重要である場合に役立ちます。
for
ループを使用して配列orderIDs
の要素を反復する次の例を考えてみます。このfor
ループの副次的効果は、ループ変数id
を使用せずにorderIDs
の要素数を計算することです。
int[] orderIDs = {34, 45, 23, 27, 15};
int total = 0;
for (int id : orderIDs) {
total++;
}
System.out.println("Total: " + total);
無名変数を使用して、使用されていない変数id
を省略または削除できます。
int[] orderIDs = {34, 45, 23, 27, 15};
int total = 0;
for (int _ : orderIDs) {
total++;
}
System.out.println("Total: " + total);
次の表に、無名変数を宣言できる場所を示します。
表8-1 有効な無名変数宣言
宣言タイプ | 無名変数を使用した例 |
---|---|
ブロック内のローカル変数宣言文 |
Queue::removeによって返される値を名前付き変数または無名変数に割り当てる必要はありません。あまり知られていないAPIによってアプリケーションで使用しない値が返されることを示すために、そうすることができます。 |
try -with-resources文のリソース指定
|
|
基本のfor 文のヘッダー
|
|
拡張for ループのヘッダー
|
|
catch ブロックの例外パラメータ
|
|
ラムダ式の仮パラメータ |
|
無名パターン
ColoredPoint
の2つのインスタンス間の距離を計算する次の例を考えてみます。
record Point(double x, double y) {}
enum Color { RED, GREEN, BLUE }
record ColoredPoint(Point p, Color c) {}
double getDistance(Object obj1, Object obj2) {
if (obj1 instanceof ColoredPoint(Point p1, Color c1) &&
obj2 instanceof ColoredPoint(Point p2, Color c2)) {
return java.lang.Math.sqrt(
java.lang.Math.pow(p2.x - p1.x, 2) +
java.lang.Math.pow(p2.y - p1.y, 2));
} else {
return -1;
}
}
この例では、ColoredPoint
レコードのColor
コンポーネントは使用しません。コードを簡略化し、読みやすさを向上させるには、無名パターン(_
)を使用してタイプ・パターンColor c1
およびColor c2
を削除できます。
double getDistance(Object obj1, Object obj2) {
if (obj1 instanceof ColoredPoint(Point p1, _) &&
obj2 instanceof ColoredPoint(Point p2, _)) {
return java.lang.Math.sqrt(
java.lang.Math.pow(p2.x - p1.x, 2) +
java.lang.Math.pow(p2.y - p1.y, 2));
} else {
return -1;
}
}
または、型パターンの型を保持し、名前だけを削除することもできます。
if (obj1 instanceof ColoredPoint(Point p1, Color _) &&
obj2 instanceof ColoredPoint(Point p2, Color _))
無名パターン変数には値がバインドされていません。したがって、次の例で強調表示された文は無効です。
if (obj1 instanceof ColoredPoint(Point p1, Color _) &&
obj2 instanceof ColoredPoint(Point p2, Color _)) {
// Compiler error: the underscore keyword '_" is only allowed to
// declare unnamed patterns, local variables, exception parameters or
// lambda parameters
System.out.println("Color: " + _);
// ...
}
また、無名パターンを最上位レベルのパターンとして使用することはできません。
// Compiler error: the underscore keyword '_' is only allowed to
// declare unnamed patterns, local variables, exception parameters or
// lambda parameters
if (obj1 instanceof _) {
// ...
}
無名パターンをswitch
式および文で使用できます。
sealed interface Employee permits Salaried, Freelancer, Intern { }
record Salaried(String name, long salary) implements Employee { }
record Freelancer(String name) implements Employee { }
record Intern(String name) implements Employee { }
void printSalary(Employee b) {
switch (b) {
case Salaried r -> System.out.println("Salary: " + r.salary());
case Freelancer _ -> System.out.println("Other");
case Intern _ -> System.out.println("Other");
}
}
パターン変数を宣言していない場合は、case
ラベルに複数のパターンを使用できます。たとえば、前のswitch
文を次のようにリライトできます。
switch (b) {
case Salaried r -> System.out.println("Salary: " + r.salary());
case Freelancer _, Intern _ -> System.out.println("Other");
}