1. Overview

In this tutorial, we’ll discuss two techniques for finding the minimum and maximum values within a 2D array using Java. A 2D array is an arrangement of elements structured like a grid. It’s an array of arrays, where each inner array represents a row in the grid.

We’ll first examine the traditional approach utilizing nested for loops. Next, we’ll explore Stream API to accomplish the same task. Both methods have advantages and disadvantages. The best choice for a particular situation depends on our needs.

2. Identifying Extreme Values Using Nested For Loops

@Test
void givenArrayWhenFindMinAndMaxUsingForLoopsThenCorrect() {
    int[][] array = {{8, 4, 1}, {2, 5, 7}, {3, 6, 9}};

    int min = array[0][0];
    int max = array[0][0];
    for (int[] row : array) {
        for (int currentValue : row) {
            if (currentValue < min) {
                min = currentValue;
            } else if (currentValue > max) {
                max = currentValue;
            }
        }
    }

    assertEquals(1, min);
    assertEquals(9, max);
}

The outer for loop iterates through each row in the 2D array. Then, the nested for loop iterates through each element within the current row. We check if the current element is less than the current minimum or greater than the current maximum, updating these values if necessary.

While simplicity makes this a viable choice, the potential inefficiency with large arrays makes it worthwhile to consider alternative approaches.

3. Identifying Extreme Values Using Stream

The Java Stream API offers a concise and declarative way to process data. We can convert the 2D array to a single Stream of elements using the flatMapToInt() method. This method transforms the 2D array into a unified Stream of individual elements, allowing us to find the min and max in a single and readable line of code using the summaryStatistics() method:

@Test
void givenArrayWhenFindMinAndMaxUsingStreamThenCorrect() {
    int[][] array = {{8, 4, 1}, {2, 5, 7}, {3, 6, 9}};

    IntSummaryStatistics stats = Arrays
      .stream(array)
      .flatMapToInt(Arrays::stream)
      .summaryStatistics();

    assertEquals(1, stats.getMin());
    assertEquals(9, stats.getMax());
}

The flatMapToInt() method flattens the nested structure of the 2D array into a Stream of individual elements.

From this unified Stream of all elements, we use the summaryStatistics() method. This method terminates the Stream and generates a summary of the contents. This summary includes the min and max but also provides the average, sum, and count of elements in the Stream.

While summaryStatistics() offers a convenient way to find both the min and max, the Stream API also provides dedicated methods min() and max() for finding the minimum and maximum element of a Stream, respectively. This approach is concise when we only need the min or max, not the other statistics.

3.1. Parallel Processing

For greater efficiency, we can use parallel processing with the Stream API. This involves utilizing multiple threads to distribute the computational workload, potentially reducing processing time in large arrays:

@Test
void givenArrayWhenFindMinAndMaxUsingParallelStreamThenCorrect() {
    int[][] array = {{8, 4, 1}, {2, 5, 7}, {3, 6, 9}};

    IntSummaryStatistics stats = Arrays
      .stream(array)
      .parallel()
      .flatMapToInt(Arrays::stream)
      .summaryStatistics();

    assertEquals(1, stats.getMin());
    assertEquals(9, stats.getMax());
}

While Stream API syntax may be less intuitive for beginners, its benefits in conciseness and performance make it a valuable tool.

4. Conclusion

In this quick article, we’ve explored two effective approaches for identifying the minimum and maximum values in a 2D array in Java. Nested for loops provide a straightforward and intuitive approach, particularly well-suited for situations where clarity and simplicity are important. On the other hand, Stream API offers a concise, expressive, and performant approach, perfect for handling large arrays.

As always, the code is available over on GitHub.