Modern Java

106. Unnamed Variables & Patterns

The single underscore _ denotes an unnamed variable or pattern in Java 22+, signaling intentionally unused parameters in lambdas, exception handlers, try-with-resources, and record deconstruction.

Java 22 (JEP 456)

Explanation

Before Java 22, developers had to name every variable even when it was never read, frequently resorting to arbitrary dummy identifiers like ignored, unused, or e1. This polluted code readability and caused compiler/linter warnings about unreferenced variables.

JEP 456 (Java 22) officially designates the underscore character _ as the unnamed variable and unnamed pattern. An unnamed variable cannot be read or referred to by name; it simply denotes that a value is accepted but deliberately ignored.

Key places where _ shines: 1. Exception catch blocks: catch (NumberFormatException _) when the exception presence is all that matters. 2. Lambdas and Streams: (k, _) -> ... when only the key is needed in a Map operation. 3. Try-with-resources: try (var _ = acquireLock()) when a scoped guard must be closed without using the instance. 4. Record Deconstruction: if (shape instanceof Point(int x, _)) when you only want component x and don't care about y. 5. Multiple unnameds in the same scope: Multiple _ variables can exist in the same block without variable shadowing or name collision errors!

Example

import java.util.Map;

public class UnnamedVariablesDemo {
    record Point(int x, int y) {}
    record Transaction(String id, double amount, String currency) {}

    public static void main(String[] args) {
        // 1. Exception catch block
        try {
            int port = Integer.parseInt("invalid");
        } catch (NumberFormatException _) {
            System.out.println("Invalid port number, using fallback default.");
        }

        // 2. Map iteration / lambdas where value is unneeded
        Map<String, String> config = Map.of("timeout", "30", "retries", "3");
        config.forEach((key, _) -> System.out.println("Config key: " + key));

        // 3. Record pattern deconstruction ignoring unwanted components
        Object obj = new Transaction("TX-992", 450.00, "USD");
        if (obj instanceof Transaction(String id, double amt, _)) {
            System.out.printf("Transaction %s: $%.2f (currency ignored)%n", id, amt);
        }

        // 4. Nested deconstruction with unnamed patterns
        Object p = new Point(10, 20);
        if (p instanceof Point(int x, _)) {
            System.out.println("X coordinate is: " + x);
        }
    }
}

Sources