はじめに
Java21あたりで入るかもしれない Unnamed Patterns and Variables(JEP 443) の先取りです。
Unnamed Patterns and Variables では、他の言語で良くある通り、アンダースコア _
で無名パターンや無名変数を記述できるようになります。
無名パターン/無名変数により以下が期待できます。
- レコードパターンの可読性向上
- 未使用変数の特定による保守性向上
Unnamed variables
次のコードでは、Order をイテレートしますが Order 自体は利用しません。
このようなケースで、未使用の変数に Unnamed variables _
を使用できます。
int acc = 0; for (Order _ : orders) { if (acc < LIMIT) { acc++; }
以下のようなケースでも _
を使用できます。
for (int i = 0, _ = sideEffect(); i < 10; i++) { ... }
次のコードはデータをデキューしますが、3 つの要素のうち 1 つしか必要としません。
未使用の変数として _
を複数回使用できます。
while (q.size() >= 3) { var x = q.remove(); var _ = q.remove(); var _ = q.remove(); var p = new Point(x, 0); }
例外を処理するが、例外自体は不要な場合は以下のように書くことができます。
String s = ...; try { int i = Integer.parseInt(s); ... } catch (NumberFormatException _) { System.out.println("Bad number: " + s); }
try-with-resources でリソースがコンテキストを表すため、コードではコンテキストを直接使用しない以下のようなケースでも _
を使用できます。
スコープを抜ければリソースは開放されます。
try (var _ = ScopedContext.acquire()) { // no use of acquired resource }
ラムダパラメータでも _
を使用できます。
以下の例では、キーに文字列ストリームの内容、値に固定値を設定したマップを生成する例です。
stream.collect(Collectors.toMap( String::toUpperCase, _ -> "NODATA"));
Unused patterns
Unused patterns は、型と変数を合わせて _
としてパターン記述します。
instanceof
のレコードパターンで以下のように書くことができます。
record Point(int x, int y) { } Object obj = new Point(1, 2); if (obj instanceof Point(int x, _)) { System.out.println(x); }
switch
で以下のように書くことができます。
switch (obj) { case Point(int x, _) -> //... ... }
以下のようなネストしたケースにおいても Unused patterns を利用できます。
record Point(int x, int y) { } enum Color { RED, GREEN, BLUE } record ColoredPoint(Point p, Color c) { } if (r instanceof ColoredPoint(Point(int x, _), _)) { // use x }
Unnamed pattern variables
Unnamed pattern variables は、型定義は記載し、変数名を _
定義します。
if (obj instanceof Point(int x, int _)) { }
前述の例は以下のように書いても同じです。
if (r instanceof ColoredPoint(Point(int x, int _), Color _)) { // use x }
Unnamed pattern variables は、複数のケースで同じアクションをするケースで便利です。
sealed abstract class Ball permits RedBall, BlueBall, GreenBall { } final class RedBall extends Ball { } final class BlueBall extends Ball { } final class GreenBall extends Ball { } record Box<T extends Ball>(T content) { } switch (b) { case Box(RedBall _), Box(BlueBall _) -> processBox(b); case Box(GreenBall _) -> stopProcessing(); case Box(_) -> pickAnotherBox(); }
case 句の最初の2つのケースでは Unnamed pattern variables を使用しています。 3番目のケースでは、Unused patterns により、残りの全てのケースにマッチさせています。
まとめ
JEP 443 としてプレビュー提案となった Unnamed Patterns and Variables を紹介しました。
_
による無名変数は、古くより検討がありましたが、 record patterns に合わせて導入の機運が高まっています。
タイミング的に、LTS となる Java21 には入らないかもしれませんが、さっさと入ってほしいものです。