Unnamed Variables and Patterns

Naveen AnamaneniUpdated · 6 min read

An unnamed variable is a variable declared with the name _ (a single underscore). It tells the reader and the compiler: "a variable is required here, but I'm not going to use it." An unnamed pattern is a _ inside a record pattern, meaning "there's a component here, and I don't care what it is." Both became standard in Java 22 (JEP 456). In this lesson, you will learn every place _ can be used, and how it lets one switch case handle several types.

Why It Exists

Java often forces you to name things you don't use: the loop variable when you only count, the exception in a catch you only log, the key in a lambda that only needs the value. Unused names are noise, and tools warn about them. _ makes the intent clear and can be used many times in the same scope, because it never really declares a name.

Where You Can Use _

PlaceExample
Local variableint _ = queue.remove();
Enhanced for loop variablefor (String _ : names) count++;
catch parametercatch (NumberFormatException _) { ... }
Lambda parametermap.forEach((_, v) -> ...)
try-with-resourcestry (var _ = new Timer()) { ... }
Type pattern in a casecase Circle _ -> ...
Component in a record patternPoint(int x, _)

It can't be used for fields, method parameters, or method names, and you can never read an unnamed variable.

Example: Everyday Uses

Let's see an example that uses _ in loops, catch, lambdas and try-with-resources:

Unused.java▶ Try it
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
 
public class Unused {
    static class Timer implements AutoCloseable {
        Timer() {
            System.out.println("timer started");
        }
 
        public void close() {
            System.out.println("timer stopped");
        }
    }
 
    public static void main(String[] args) {
        List<String> names = List.of("Navika", "Srihitha", "Advitha");
        int count = 0;
        for (String _ : names) {
            count++;
        }
        System.out.println("count = " + count);
 
        try {
            Integer.parseInt("abc");
        } catch (NumberFormatException _) {
            System.out.println("not a number");
        }
 
        Map<String, Integer> marks =
            new TreeMap<>(Map.of("Navika", 91, "Advitha", 78));
        marks.replaceAll((_, v) -> v + 5);
        System.out.println(marks);
 
        try (var _ = new Timer()) {
            System.out.println("working");
        }
    }
}
Output
count = 3
not a number
{Advitha=83, Navika=96}
timer started
working
timer stopped

Explanation:

  • The loop only counts, so the element is unnamed.
  • The catch only needs to know the exception happened.
  • replaceAll((_, v) -> v + 5) adds 5 to every value; the key isn't needed.
  • try-with-resources still calls close() on the unnamed Timer. That's useful for resources that only matter for their opening and closing, such as a lock holder or a timer.

Unnamed Patterns in Switch

In a switch, _ lets one case handle several types when it doesn't need the value. Before Java 22 this wasn't possible, because each type pattern needed its own variable:

Corners.java▶ Try it
public class Corners {
    sealed interface Shape permits Circle, Square, Triangle { }
    record Circle(double r) implements Shape { }
    record Square(double side) implements Shape { }
    record Triangle(double b, double h) implements Shape { }
    record Point(int x, int y) { }
 
    static String corners(Shape s) {
        return switch (s) {
            case Circle _ -> "no corners";
            case Square _, Triangle _ -> "has corners";
        };
    }
 
    static String kind(Object o) {
        return switch (o) {
            case Integer _, Long _ -> "whole number";
            case Double _, Float _ -> "decimal";
            default -> "other";
        };
    }
 
    public static void main(String[] args) {
        System.out.println(corners(new Triangle(2, 3)));
        System.out.println(kind(5L));
        System.out.println(kind(2.5f));
 
        Object o = new Point(3, 4);
        if (o instanceof Point(int x, _)) {
            System.out.println("x = " + x);
        }
    }
}
Output
has corners
whole number
decimal
x = 3

Explanation: case Square _, Triangle _ matches either type. It's still exhaustive: together with Circle _, every Shape is covered. Point(int x, _) takes only the first component; _ stands for the whole pattern of the second.

The Rules

A case with several patterns can't bind a named variable, because the variable wouldn't be set when the other pattern matched:

Compiler output
U5.java:4: error: illegal fall-through from a pattern
            case Integer _, String s -> "x";
                            ^
  (the current case label is missing a break)
1 error

And an unnamed variable can never be read:

Compiler output
U2.java:4: error: underscore not allowed here
        System.out.println(_);
                           ^
1 error

In very old code (Java 8 and earlier), _ was a legal variable name. Since Java 9 it has been a keyword, which is why it was free to take this new meaning.

Common Mistakes

Trying to read _. It isn't a variable you can use; give it a real name if you need it.

Naming one variable in a multi-pattern case. All patterns in a case with several patterns must be unnamed.

Using _ for method parameters. That isn't allowed; only local variables, lambda parameters, catch parameters, loop variables, resources and patterns can be unnamed.

Hiding real errors. catch (Exception _) { } makes failures invisible.

Interview Corner

What are unnamed variables and patterns?

Introduced as standard in Java 22, the underscore _ declares a variable or pattern that is required by the syntax but not used. It can be used for local variables, enhanced-for variables, catch parameters, lambda parameters, try-with-resources resources, type patterns (case Circle _) and record pattern components (Point(int x, _)). It can appear several times in the same scope and can never be read. In switch, it allows one case to list several patterns, such as case Square _, Triangle _ ->, as long as none of them binds a named variable.

Practice

  1. Easy: Use _ in an enhanced for loop that prints "Hello" once for each name in a list. Then explain why the counter i in for (int i = 0; i < 5; i++) can't be named _.
  2. Harder: Write a switch over a sealed Event interface with Click, KeyPress and Scroll records, where Click and KeyPress share one case using unnamed patterns.

Quick check: Unnamed variables

4 questions
1What does _ mean in catch (IOException _)?
2Can _ be used twice in the same method?
3Which case compiles?
4In which Java version did unnamed variables become standard?

Key Takeaways

Was this tutorial helpful?

Lesson 461 of 482