unnamed variables and patternsunnamed variables and patterns
HappyCoders Glasses

Unnamed Variables and Patterns in Java

Sven Woltmann
Sven Woltmann
Last update: June 7, 2026

In this article, you will learn:

  • What is an unnamed variable, and what purpose does it serve?
  • What are unnamed patterns and unnamed pattern variables, and what purpose do they serve?
  • How can you write switch expressions more concisely with unnamed pattern variables?

Unnamed variables and patterns were introduced as a preview feature in Java 21 as part of Project Amber. They were finalized in Java 22.

Unnamed Variables

It often happens that we have to define a variable that we don’t need later. Here are two examples that you probably know:

Example 1: Exceptions – here, we don’t use e:

try {
    int number = Integer.parseInt(string);
} catch (NumberFormatException e) {
    System.err.println("Not a number");
}Code language: Java (java)

Example 2: Map.computeIfAbsent() – this time, we don’t use k:

map.computeIfAbsent(key, k -> new ArrayList<>()).add(value);Code language: Java (java)

As of Java 22 (or as of Java 21 with preview features enabled), we no longer have to name such variables but may (as has long been common in other programming languages) use the underscore (_) instead:

Here is the exception example with an unnamed variable:

try {
    int number = Integer.parseInt(string);
} catch (NumberFormatException _) {
    System.err.println("Not a number");
}Code language: Java (java)

And the computeIfAbsent() example:

map.computeIfAbsent(key, _ -> new ArrayList<>()).add(value);Code language: Java (java)

With an exception, one may argue about the pros and cons of an unnamed variable. We are used to naming an exception with “e” or letting our IDE do that automatically.

With computeIfAbsent(), on the other hand, I always wondered how to name the variable I didn’t need. Sometimes it became a k (for “key”), sometimes an ignored, and sometimes a __ (double underscore¹). This is where the unnamed variable is a big help.

¹ The single underscore has not been allowed as a variable name since Java 9, in preparation for this very feature.

But catch blocks and lambda parameters aren't the only places where the underscore helps. Let's look at the other use cases.

The Loop Variable in a for Loop

Sometimes, in a for loop, we only care about how often something happens – not with what. Here's an example: we want to count how many elements an Iterable contains. Since Iterable has no size() method, we have to count the elements by iterating over them – and to do that, we have to name a loop variable we don't actually need:

int count = 0;
for (Order order : orders) {
    count++;
}Code language: Java (java)

We don't need the order variable – so we replace it with the underscore:

int count = 0;
for (Order _ : orders) {
    count++;
}Code language: Java (java)

Local Variables Whose Value We Don't Need

We can also leave an ordinary local variable unnamed – for example, when we're only interested in the side effect of a method call. Imagine we take three elements from a queue but only need the first two:

while (queue.size() >= 3) {
    var first  = queue.remove();
    var second = queue.remove();
    var _      = queue.remove(); // removes the third element, which we don't need
    process(first, second);
}Code language: Java (java)

Resources in try-with-resources

A try-with-resources block closes its resource automatically – even if we never access it directly within the block. A typical example is a lock that we only want to hold, not call:

try (var _ = lock.acquire()) {
    // critical section – the resource is released automatically on exit
}Code language: Java (java)

This way, you make it clear: the resource matters because of its side effect (acquiring and releasing it), but we don't access it within the block.

Unnamed Patterns and Pattern Variables

By the way, the feature is not called “Unnamed Variables,” but “Unnamed Variables & Patterns” and thus has a lot more to offer – namely in combination with the features Record Patterns and Pattern Matching for Switch, which were finalized in Java 21.

The variable y is not needed in the “then block” of the following code example:

if (object instanceof Position(int x, int y)) {
    System.out.println("object is a position, x = " + x);
}Code language: Java (java)

Again, we can replace y with an underscore:

if (object instanceof Position(int x, int _)) {
    System.out.println("object is a position, x = " + x);
}Code language: Java (java)

This is called an “unnamed pattern variable.”

We can even go one step further and replace the entire partial pattern int y with an underscore:

if (object instanceof Position(int x, _)) {
    System.out.println("object is a position, x = " + x);
}Code language: Java (java)

This is called an “unnamed pattern.”

In the previous example, this doesn’t have much effect; however, using nested patterns, it can save a lot of space. In the following example, we use only the variables x1 and y1, while x2 and y2 are unused:

if (object instanceof Path(Position(int x1, int y1), Position(int x2, int y2))) {
    System.out.printf("object is a path starting at x = %d, y = %d%n", x1, y1);
}Code language: Java (java)

Here we can replace the complete second Position pattern with the underscore:

if (object instanceof Path(Position(int x1, int y1), _)) {
    System.out.printf("object is a path starting at x = %d, y = %d%n", x1, y1);
}Code language: Java (java)

That, after all, represents a significant improvement.

Unnamed Pattern Variables and Pattern Matching for Switch

Here is an example with unused variables in Pattern Matching for Switch:

switch (obj) {
    case Byte    b -> System.out.println("Integer number");
    case Short   s -> System.out.println("Integer number");
    case Integer i -> System.out.println("Integer number");
    case Long    l -> System.out.println("Integer number");

    case Float  f -> System.out.println("Floating point number");
    case Double d -> System.out.println("Floating point number");

    default -> System.out.println("Not a number");
}Code language: Java (java)

Again, we may replace all variable names with underscores:

switch (obj) {
    case Byte    _ -> System.out.println("Integer number");
    case Short   _ -> System.out.println("Integer number");
    case Integer _ -> System.out.println("Integer number");
    case Long    _ -> System.out.println("Integer number");

    case Float  _ -> System.out.println("Floating point number");
    case Double _ -> System.out.println("Floating point number");

    default -> System.out.println("Not a number");
}Code language: Java (java)

We can even go one step further and combine all cases with the same actions:

switch (obj) {
    case Byte _, Short _, Integer _, Long _ -> System.out.println("Integer number");
    case Float _, Double _                  -> System.out.println("Floating point number");

    default -> System.out.println("Not a number");
}Code language: Java (java)

And this is – besides the more concise notation – another significant advantage of the unnamed pattern variable! With named variables, this would not have been possible. The following code is not valid:

switch (obj) {
    // Not allowed!          
    case Byte b, Short s, Integer i, Long l -> System.out.println("Integer number");
    case Float f, Double d                  -> System.out.println("Floating point number");

    default -> System.out.println("Not a number");
}Code language: Java (java)

This code results in the following compiler error:

error: illegal fall-through from a pattern
  case Byte b, Short s, Integer i, Long l -> System.out.println("Integer number");
               ^Code language: plaintext (plaintext)

The crucial difference is that named variables can be accessed from subsequent code, while unnamed variables may not be accessed. Since the compiler does not know which pattern will match at runtime, it also does not know which of the variables b, s, i, and l may be accessed. Therefore, it allows only one named variable per case but any number of unnamed variables.

Conclusion

Unnamed variables and patterns solve a small but everyday annoyance: time and again, we have to declare variables that we don't use at all – the exception in the catch block, the key in computeIfAbsent(), the loop variable when we're just counting.

With the underscore, you explicitly show that a variable is intentionally left unused. Your code becomes more concise and, at the same time, more expressive.

On top of that, you can combine multiple case labels with the same code – which works only with unnamed pattern variables, not with named ones.

Unnamed Variables & Patterns are defined in JDK Enhancement Proposal 456.