eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Overview

The release of Java 21 SE introduces an exciting preview feature: unnamed patterns and variables (JEP 443). This new addition allows us to reduce boilerplate code when side effects are our only concern.

Unnamed patterns are an improvement over Record Patterns In Java 19 and Pattern Matching for Switch. We should also be familiar with the Record functionality introduced as a preview in Java 14.

In this tutorial, we’ll delve into how we can use these new features to improve our code quality and readability.

2. Purpose

Usually, when working with complex objects, we don’t need all the data they hold at all times. Ideally, we receive from an object only what we need, but that’s rarely the case. Most of the time, we end up using one small part of what we’ve been given.

Examples of this can be found all over OOP, evidentiated by the Single Responsibility Principle. The unnamed patterns and variable feature is Java’s latest attempt at tackling that on a lower scale.

Since this is a preview feature, we must ensure we enable it. In Maven, this is done by modifying the compiler plugin configuration to include the following compiler argument:

<compilerArgs>
    <arg>--enable-preview</arg>
</compilerArgs>

3. Unnamed Variables

While new to Java, this feature is well-loved in other languages such as Python and Go. Since Go isn’t precisely object-oriented, Java takes the lead in introducing this feature in the world of OOP.

Unnamed variables are used when we care only about an operation’s side effects. They can be defined as many times as needed, but they cannot be referenced from a later point.

3.1. Enhanced For Loop

For starters, let’s say we have a simple Car record:

public record Car(String name) {}

We then need to iterate through a collection of cars to count all cars and do some other business logic:

for (var car : cars) {
    total++;
    if (total > limit) {
        // side effect
    }
}

While we need to go through every element in the car collection, we don’t need to use it. Naming the variable makes the code harder to read, so let’s try the new feature:

for (var _ : cars) {
    total++;
    if (total > limit) {
        // side effect
    }
}

This makes it clear to the maintainer that the car isn’t used. Of course, this can also be used with a basic for loop:

for (int i = 0, _ = sendOneTimeNotification(); i < cars.size(); i++) {
    // Notify car
}

Note, however, that the sendOneTimeNotification() gets called only once. The method must also return the same type as the first initialization (in our case, i).

3.2. Assignment Statements

We can also use unnamed variables with assignment statements. This is most useful when we need both a function’s side effects and some return values (but not all).

Let’s say we need a method that removes the first three elements in a queue and returns the first one:

static Car removeThreeCarsAndReturnFirstRemoved(Queue<Car> cars) {
    var car = cars.poll();
    var _ = cars.poll();
    var _ = cars.poll();
    return car;
}

As we can see in the example above, we can use multiple assignments in the same block. We can also ignore the result of the poll() calls, but this way, it’s more readable.

3.3. Try-Catch Block

Possibly, the most helpful functionality of unnamed variables comes in the form of unnamed catch blocks. Many times, we want to handle exceptions without actually needing to know what the exception contains.

With unnamed variables, we no longer have to worry about that:

try {
    someOperationThatFails(car);
} catch (IllegalStateException _) {
    System.out.println("Got an illegal state exception for: " + car.name());
} catch (RuntimeException _) {
    System.out.println("Got a runtime exception!");
}

They also work for multiple exception types in the same catch:

catch (IllegalStateException | NumberFormatException _) { }

3.4. Try-With Resources

While encountered less than try-catch, the try-with syntax also benefits from this. For example, when working with databases, we don’t usually need the transaction object.

To take a better look at this, let’s first create a mock transaction:

class Transaction implements AutoCloseable {

    @Override
    public void close() {
        System.out.println("Closed!");
    }
}

Let’s see how this works:

static void obtainTransactionAndUpdateCar(Car car) {
    try (var _ = new Transaction()) {
        updateCar(car);
    }
}

And, of course, with multiple assignments:

try (var _ = new Transaction(); var _ = new FileInputStream("/some/file"))

3.5. Lambda Parameters

Lambda functions offer, by nature, a great way of reutilizing code. It is only natural that, by offering this flexibility, we end up having to address cases that don’t interest us.

A great example of this is the computeIfAbsent() method from the Map interface. It checks if a value exists in the map or computes a new one based on a function.

While useful, we usually don’t need the lambda’s parameter. It’s the same as the key passed to the initial method:

static Map<String, List<Car>> getCarsByFirstLetter(List<Car> cars) {
    Map<String, List<Car>> carMap = new HashMap<>();
    cars.forEach(car ->
        carMap.computeIfAbsent(car.name().substring(0, 1), _ -> new ArrayList<>()).add(car)
    );
    return carMap;
}

This works with multiple lambdas and multiple lambda parameters:

map.forEach((_, _) -> System.out.println("Works!"));

4. Unnamed Patterns

Unnamed patterns have been introduced as an enhancement to Record Pattern Matching. They address an issue quite apparent: we usually don’t need every field in records we deconstruct.

To explore this topic, let’s first add a class called Engine:

abstract class Engine { }

The engine can be gas-based, electric, or hybrid:

class GasEngine extends Engine { }
class ElectricEngine extends Engine { }
class HybridEngine extends Engine { }

Finally, let’s extend the Car to support parameterized types so we can reuse it depending on the engine type. We’ll also add a new field called color:

public record Car<T extends Engine>(String name, String color, T engine) { }

4.1. instanceof

When deconstructing records with patterns, unnamed patterns enable us to ignore fields we don’t need.

Let’s say we get an object, and if it’s a car, we want to get its color:

static String getObjectsColor(Object object) {
    if (object instanceof Car(String name, String color, Engine engine)) {
        return color;
    }
    return "No color!";
}

While this works, it’s hard to read, and we’re defining variables we don’t need. Let’s see how this looks with unnamed patterns:

static String getObjectsColorWithUnnamedPattern(Object object) {
    if (object instanceof Car(_, String color, _)) {
        return color;
    }
    return "No color!";
}

Now it’s clear we just need a car’s color.

This also works for simple instanceof definitions, but it’s not quite as useful:

if (car instanceof Car<?> _) { }

4.2. Switch Patterns

Deconstructing with switch patterns also allows us to ignore fields:

static String getObjectsColorWithSwitchAndUnnamedPattern(Object object) {
    return switch (object) {
        case Car(_, String color, _) -> color;
        default -> "No color!";
    };
}

Additionally to this, we can also handle parameterized cases. For example, we can handle different engine types in different switch cases:

return switch (car) {
    case Car(_, _, GasEngine _) -> "gas";
    case Car(_, _, ElectricEngine _) -> "electric";
    case Car(_, _, HybridEngine _) -> "hybrid";
    default -> "none";
};

We can also pair cases together more easily and also with guards:

return switch (car) {
    case Car(_, _, GasEngine _), Car(_, _, ElectricEngine _) when someVariable == someValue -> "not hybrid";
    case Car(_, _, HybridEngine _) -> "hybrid";
    default -> "none";
};

5. Conclusions

Unnamed patterns and variables are a great addition that addresses the Single Responsibility Principle. It’s a breaking change for versions before Java 8, but later versions aren’t affected since naming variables _ is not permitted.

The feature kicks it out of the park by reducing boilerplate code and improving readability while making everything seem simpler.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)
2 Comments
Oldest
Newest
Inline Feedbacks
View all comments