Java 22 Unnamed Variables and Patterns with _

Introduction Java code often has to declare a variable it will never use: the exception in a catch block which is handled the same way whatever it says, a lambda parameter the lambda ignores, or a record component in a record patternClick to read: record pattern which the code does not need. Giving such variables names like ignored or unused adds noise, and tools warn about unused variables. Java 22Click to read tutorial: Overview of New Features in Java 22 (JEP 456), after a preview in Java 21, finalized unnamed variables and patterns: the underscore _ declares a variable or pattern without a name, which says clearly "I do not need this". This tutorial explains them with examples - in catch blocks, lambdas, loops and try-with-resources, in record patterns and switch cases - and the rules for where _ can be used. Unnamed variables An unnamed variable is declared with _ instead of a name. It is allowed wherever a local variable is declared but its value is not needed -
Unused variables replaced by _
//UnnamedVariablesDemo.java
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

public class UnnamedVariablesDemo {
  public static void main(String[] args) {
    // catch: the exception itself is not needed
    String input = "12a";
    int value;
    try {
      value = Integer.parseInt(input);
    } catch (NumberFormatException _) {
      value = -1;
    }
    System.out.println("Parsed: " + value);

    // lambda parameters: only one of two is used
    BiFunction<String, Integer, String> firstOnly = (name, _) -> name.toUpperCase();
    System.out.println(firstOnly.apply("tom", 42));

    // enhanced for: count elements without using them
    int count = 0;
    for (String _ : List.of("a", "b", "c")) count++;
    System.out.println("Counted " + count);

    // several _ in the same scope are fine - they are all unnamed
    Map<String, Integer> lengths = List.of("Java", "Duke").stream()
        .collect(Collectors.toMap(s -> s, String::length, (a, _) -> a));
    System.out.println(lengths);
  }
}
 OUTPUT of the above code
Parsed: -1
TOM
Counted 3
{Java=4, Duke=4}
Explanation of the code
  • catch (NumberFormatException _) handles the exception without naming it. Since the variable has no name, it cannot be used by mistake, and IDEs do not warn about an unused variable.
  • In the lambda (name, _) -> ... and the merge function (a, _) -> a, the underscore marks the parameter which is ignored. Several unnamed variables can exist in the same scope, unlike named ones.
  • Unnamed variables are also allowed for local variables with an initializer whose side effect matters (var _ = queue.remove();), in basic for loops and in try-with-resources (try (var _ = lock.acquire())).
Unnamed patterns In patterns, _ has two forms. An unnamed pattern, a bare _, matches any value of a record component without binding it. An unnamed pattern variable, such as Circle _, checks the type but does not bind a variable -
_ in record patterns and switch cases
//UnnamedPatternsDemo.java
public class UnnamedPatternsDemo {
  sealed interface Shape permits Circle, Square, Rect { }
  record Point(int x, int y) { }
  record Circle(Point center, double radius) implements Shape { }
  record Square(Point corner, double side) implements Shape { }
  record Rect(Point corner, double width, double height) implements Shape { }

  static String size(Shape shape) {
    return switch (shape) {
      case Circle(_, double r) -> "circle of radius " + r;          // center not needed
      case Square(_, double s) -> "square of side " + s;
      case Rect(_, double w, double h) when w == h -> "a square-shaped rectangle";
      case Rect _ -> "a rectangle";                                 // type only, no binding
    };
  }

  static boolean isRound(Shape shape) {
    return switch (shape) {
      case Circle _ -> true;
      case Square _, Rect _ -> false;     // several patterns in one case: allowed with _
    };
  }

  public static void main(String[] args) {
    Shape[] shapes = {new Circle(new Point(0, 0), 2), new Square(new Point(1, 1), 3), new Rect(new Point(0, 0), 4, 4), new Rect(new Point(0, 0), 2, 5)};
    for (Shape s : shapes) {
      System.out.println(size(s) + ", round = " + isRound(s));
    }
  }
}
 OUTPUT of the above code
circle of radius 2.0, round = true
square of side 3.0, round = false
a square-shaped rectangle, round = false
a rectangle, round = false
case Square _, Rect _ shows a capability unnamed patterns made possible: a single case can list several patterns, as long as none of them binds a variable - because the code after the arrow could not know which variable was bound.
Rules
  • An unnamed variable cannot be read - there is no name to read it by.
  • _ cannot be used for fields, method parameters (but lambda parameters are fine) or anywhere a name is needed to refer to something.
  • Since Java 9, _ has been a reserved keyword, so no existing code can use it as an ordinary identifier.
Using _ where it is not allowed
//UnnamedErrors.java
public class UnnamedErrors {
  int _ = 5;                           // fields cannot be unnamed

  void method(String _) { }            // method parameters cannot be unnamed

  void read() {
    var _ = 42;
    System.out.println(_);             // an unnamed variable cannot be used
  }
}
 OUTPUT on compiling the above code
UnnamedErrors.java:3: error: underscore not allowed here
  int _ = 5;                           // fields cannot be unnamed
      ^
UnnamedErrors.java:5: error: underscore not allowed here
  void method(String _) { }            // method parameters cannot be unnamed
                     ^
UnnamedErrors.java:9: error: underscore not allowed here
    System.out.println(_);             // an unnamed variable cannot be used
                       ^
3 errors
Summary In this tutorial we saw how unnamed variables and patterns, final in Java 22, use _ to mark variables and pattern components which are not needed. We used unnamed variables in a catch block, lambda parameters and an enhanced for loop, and unnamed patterns in record patterns and switch cases - including a single case with several type patterns. Lastly, we went through the rules, with the compiler errors for using _ where it is not allowed. Next, read about launching multi-file source-code programsClick to read tutorial: Java 22: Run Multi-File Programs Without Compiling.