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. Introduction

In this tutorial, we’ll understand the problem of reversing rows of a 2d array and solve it using a few alternatives using built-in Java libraries.

2. Understanding the Problem

Using 2d arrays is a common task for programmers. For instance, financial spreadsheet software is typically structured as a 2d array where each position represents a number or text. Additionally, in digital arts and photography, the images are often stored as a 2d array, where each position represents a color intensity.

When manipulating a 2d array, a common operation is to reverse all of its rows. For example, in Google Spreadsheets we have the functionality of reversing the spreadsheet row-wise. Moreover, in digital arts and photography, we can find the vertical symmetric part of an image by reversing all of its rows.

Other applications of reversing rows happen when we have a Stream of elements in Java and want to create a reversed version of that Stream or collect it in another collection in the reversed order.

The problem’s definition is quite simple: we want each row of a 2d array reversed so the first element swaps positions with the last, and so on. In other words, we want to transform the input into its vertical symmetry. Noticeably, the problem isn’t related to the reverse natural order of elements but to the reverse order that they appear in the input.

3. Reversing Rows In-Place

To help understand how to reverse rows in place, we can think of each row of a 2d array as a 1d array. Hence, the algorithm for the 1d array is straightforward: we simply swap the current index’s element with the one in its symmetric index until we reach the middle element.

For instance, one solution to the problem is:

original -5 4 3 -2 7
reversed 7 -2 3 4 -5

We’ve swapped elements in indexes 0 with 4 and 1 with 3. The middle element doesn’t have symmetry, so it stays in the same index.

Therefore, if we call the reverse 1d algorithm for each row of the 2d array, then we’ll solve for the 2d case.

3.1. Using Java for Loops

With the idea from the previous section, let’s look at the source code:

public static void reverseRowsUsingSimpleForLoops(int[][] array) {
    for (int row = 0; row < array.length; row++) {
        for (int col = 0; col < array[row].length / 2; col++) {
            int current = array[row][col];
            array[row][col] = array[row][array[row].length - col - 1];
            array[row][array[row].length - col - 1] = current;
        }
    }
}

The inner for loop solves the reverse problem for the 1d array. Hence, we iterate through each element, swapping it with its symmetric element, which is the one at the column array[row].length – col – 1, until we reach the middle index.

The outer loop calls that algorithm to reverse a 1d array for each row of the input.

We can verify the results using a JUnit 5 test and AssertJ matchers:

@Test
void givenArray_whenCallReverseRows_thenAllRowsReversed() {
    int[][] input = new int[][] { { 1, 2, 3 }, { 3, 2, 1 }, { 2, 1, 3 } };

    int[][] expected = new int[][] { { 3, 2, 1 }, { 1, 2, 3 }, { 3, 1, 2 } };
    reverseRowsUsingSimpleForLoops(input);

    assertThat(input).isEqualTo(expected);
}

3.2. Using Nested Java 8 IntStreams

Similarly to the previous for loop solution, we can use Java 8 Streams to reverse 2d arrays:

public static void reverseRowsUsingStreams(int[][] array) {
    IntStream.range(0, array.length)
      .forEach(row -> IntStream.range(0, array[row].length / 2)
          .forEach(col -> {
              int current = array[row][col];
              array[row][col] = array[row][array[row].length - col - 1];
              array[row][array[row].length - col - 1] = current;
          }));
}

Notably, the main logic stays the same – we swap elements with their symmetric in the array.

The only difference is that we use a combination of IntStream.range() and forEach() to iterate over a stream using indexes. Hence, we can just swap elements in the innermost forEach()’s lambda expression.

3.3. Using the Built-In Collections.reverse() Method

We can also use the built-in reverse() method to help with this task:

public static void reverseRowsUsingCollectionsReverse(int[][] array) {
    for (int row = 0; row < array.length; row++) {
        List <Integer> collectionBoxedRow = Arrays.stream(array[row])
            .boxed()
            .collect(Collectors.toList());

        Collections.reverse(collectionBoxedRow);

        array[row] = collectionBoxedRow.stream()
            .mapToInt(Integer::intValue)
            .toArray();
    }
}

First, like in previous approaches, we start by looping the original 2d array.

Then we box each row from int[] to List<Integer> and save it. We do that because Collections.reverse() only works for collections of objects, and Java doesn’t have a public API that reverts int[] types in place.

Finally, we unbox the reversed boxed row using the mapToInt() and toArray() methods and assign it to the original array at the index row.

Conversely, the solution becomes clearer if we accept List<List<Integer>> as an argument, so we don’t need to convert List to array and vice-versa:

public static void reverseRowsUsingCollectionsReverse(List<List<Integer>> array) {
    array.forEach(Collections::reverse);
}

4. Reversing Rows During a Stream Execution

So far, we’ve seen ways to reverse an array in place. However, sometimes we don’t want to mutate the input, which is the case when working with Java Streams.

In this section, we’ll create a customized mapper and collect functions to reverse rows of a 2d array.

4.1. Creating a Reversed Order Mapper

Let’s first look at how to create a function that returns the input list in reverse order:

static <T> List <T> reverse(List<T> input) {
    Object[] tempArray = input.toArray();

    Stream<T> stream = (Stream<T>) IntStream.range(0, temp.length)
        .mapToObj(i -> temp[temp.length - i - 1]);

    return stream.collect(Collectors.toList());
}

The method accepts a List of a generic type T and returns a reversed version of it. Using generics here helps to work with streams of any type.

The algorithm starts by creating a temporary array of Object with the input content. Then, we revert its elements by remapping each element to its symmetric, similar to what we did in Section 3.1. Finally, we collect the results into a list and return it.

Now, we can use reverse() inside a stream of a 2d array:

List<List<Integer>> array = asList(asList(1, 2, 3), asList(3, 2, 1), asList(2, 1, 3));

List<List<Integer>> result = array.stream()
  .map(ReverseArrayElements::reverse)
  .collect(Collectors.toList());

We used reverse() as a lambda function of the map() method in a stream opened with the original 2d array. Then, we collect the results reversed to a new 2d array.

4.2. Implementing a Reversed Order Collector

We can achieve the same using customized collectors. Let’s look at how it works:

static <T> Collector<T, ? , List<T>> toReversedList() {
    return Collector.of(
        ArrayDeque::new,
        (Deque <T> deque, T element) -> deque.addFirst(element),
        (d1, d2) -> {
            d2.addAll(d1);
            return d2;
        },
        ArrayList::new
    );
}

The method above returns a collector, so we can use it inside the Stream’s collect() method and get the elements of an input list reversed. To do so, we used the Collector.of() method passing 4 arguments:

  1. A Supplier of ArrayDeque that we’ll use to help us revert the input. The choice of ArrayDeque is because it provides efficient insertion at the first index.
  2. A function that accumulates each input array element, adding it to the first position of an accumulator ArrayDeque.
  3. Another function that combines the result of one accumulator ArrayDeque, d1, with another accumulator, d2. Then, we return d2.
  4. After combining the intermediate results, we convert the ArrayDeque d2 into an ArrayList using the finisher function ArrayList::new.

In short, we read from left to right on the input array and add its elements to the first position of an intermediate ArrayDeque. This guarantees that at the end of execution, the accumulated ArrayDeque will contain the reversed array. Then, we convert it to a list and return.

Then, we can use toReversedList() inside a stream:

List<List<Integer>> array = asList(asList(1, 2, 3), asList(3, 2, 1), asList(2, 1, 3));

List<List<Integer>> result = array.stream()
    .map(a -> a.stream().collect(toReversedList()))
    .collect(Collectors.toList());

We can pass toReversedList() directly into collect() opened in a stream of the original 2d array rows. Then, we collect the reversed rows into a new list to produce the final result.

5. Conclusion

In this article, we explored several algorithms for reversing rows of a 2d array in place. Additionally, we created customized mappers and collectors for reversing rows and used them inside 2d array streams.

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)