How to Find the Minimum Element in an Array in Java

Finding the smallest value in an array is the mirror image of finding the maximum — and it's every bit as common in interviews and real code.

This guide walks through the optimal linear-scan approach, alternative modern methods using streams, and the subtle mistakes that trip up even experienced developers.

Advertisement

Problem Statement

Given an array such as {45, 12, 78, 3, 25}, the task is to identify the smallest value present — here, 3.

As with maximum-finding, the optimal solution is a single O(n) pass that tracks the smallest value encountered so far.

Method 1: Linear Scan (Optimal Approach)

int[] numbers = {45, 12, 78, 3, 25};

int min = numbers[0];

for (int i = 1; i < numbers.length; i++) {
    if (numbers[i] < min) {
        min = numbers[i];
    }
}

System.out.println("Minimum element: " + min);

The loop starts at index 1 because the first element is already assigned as the initial minimum, making a self-comparison at index 0 unnecessary.

Method 2: Enhanced For Loop

int min = numbers[0];

for (int num : numbers) {
    if (num < min) {
        min = num;
    }
}

This produces the same result with cleaner syntax and is commonly preferred when the array index isn't required.

Method 3: Java Streams

import java.util.Arrays;

int min = Arrays.stream(numbers)
                .min()
                .getAsInt();

As with max(), prefer .orElse(defaultValue) instead of .getAsInt() if the array might be empty.

int min = Arrays.stream(numbers)
                .min()
                .orElse(Integer.MAX_VALUE);

Method 4: Collections.min() for Lists

If you're working with a List<Integer> rather than a primitive array:

import java.util.Collections;
import java.util.List;

List<Integer> list = List.of(45, 12, 78, 3, 25);

int min = Collections.min(list);

Step-by-Step Explanation

Initialize min

Set min to the first element.

int min = numbers[0];

This provides a valid starting comparison point.

Loop and compare

For each subsequent element:

if (numbers[i] < min) {
    min = numbers[i];
}

checks whether the current element is smaller than the smallest value found so far.

If true, update min.

Final result

After the complete traversal, min contains the smallest value in the array.

Internal Working (Memory View)

For the array:

{45, 12, 78, 3, 25}

Execution proceeds like this:

Start:
min = 45

i = 1
12 < 45
Yes
min = 12

i = 2
78 < 12
No

i = 3
3 < 12
Yes
min = 3

i = 4
25 < 3
No

Final:
min = 3

Only one comparison is performed for each element.

The min variable stays on the stack and is updated whenever a smaller value is encountered.

Real-Life Analogy

Think of finding the shortest student in a classroom lineup.

You begin by assuming the first student is the shortest.

As each new student steps forward, you compare their height with the current shortest person.

Whenever someone shorter appears, you update your record.

By the end of the lineup, you've identified the shortest student without ever sorting the entire class. You may also find Find Second Smallest Element in an Array in Java useful.

Best Practices

  • Use the linear scan (O(n)) approach—it is optimal and avoids unnecessary sorting.

  • Always guard against empty arrays before accessing numbers[0].

  • Use Arrays.stream(arr).min().orElse(Integer.MAX_VALUE) for concise and safe stream-based code.

  • If you need both the minimum and maximum values, find them together in a single loop instead of traversing the array twice.

Common Mistakes

Initializing min to 0

int min = 0;

This breaks for arrays containing only positive numbers greater than zero because 0 would incorrectly remain the minimum.

Always initialize min using the first array element.

Sorting the array first

Sorting just to access the first element increases the time complexity from O(n) to O(n log n) unnecessarily.

Ignoring empty arrays

Trying to access:

numbers[0]

on an empty array throws ArrayIndexOutOfBoundsException.

Confusing < and >

Copying maximum-element logic and forgetting to change the comparison operator is a very common interview mistake.

Expert Tips

  • Finding both the minimum and maximum values in the same loop is a common interview optimization.

int min = numbers[0];
int max = numbers[0];

for (int i = 1; i < numbers.length; i++) {

    if (numbers[i] < min) {
        min = numbers[i];
    }

    if (numbers[i] > max) {
        max = numbers[i];
    }
}

This still runs in O(n) time while avoiding a second traversal.

  • For custom objects, use:

Collections.min(
    employees,
    Comparator.comparing(Employee::getSalary)
);
  • Be careful when initializing with sentinel values like Integer.MAX_VALUE or Integer.MIN_VALUE. Initializing with the first array element is generally safer and easier to understand.

Comparison Table

Method Time Complexity Space Complexity Recommended?
Linear scan O(n) O(1) ✅ Yes – Optimal
Enhanced for loop O(n) O(1) ✅ Yes
Streams .min() O(n) O(1) ✅ Yes
Sort then take first element O(n log n) Varies ❌ Inefficient

Test It With TestNG — Including the Classic Bug

Here is a small utility with a correct min() and max(), plus the deliberately buggy "start from 0" versions from the Common Mistakes section, so the tests can show exactly what goes wrong:

public final class ArrayStats {
    private ArrayStats() { }

    public static int max(int[] numbers) {
        requireNotEmpty(numbers);
        int max = numbers[0];
        for (int i = 1; i < numbers.length; i++) {
            if (numbers[i] > max) max = numbers[i];
        }
        return max;
    }

    public static int min(int[] numbers) {
        requireNotEmpty(numbers);
        int min = numbers[0];
        for (int i = 1; i < numbers.length; i++) {
            if (numbers[i] < min) min = numbers[i];
        }
        return min;
    }

    /** The common bug: starting from 0 instead of the first element. */
    public static int maxStartingFromZero(int[] numbers) {
        int max = 0;
        for (int n : numbers) if (n > max) max = n;
        return max;
    }

    public static int minStartingFromZero(int[] numbers) {
        int min = 0;
        for (int n : numbers) if (n < min) min = n;
        return min;
    }

    private static void requireNotEmpty(int[] numbers) {
        if (numbers == null || numbers.length == 0) {
            throw new IllegalArgumentException("Array must contain at least one element");
        }
    }
}
import java.util.Arrays;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class ArrayStatsTest {

    @DataProvider(name = "arrays")
    public Object[][] arrays() {
        return new Object[][] {
            // input                         expected min  expected max
            { new int[]{45, 12, 78, 3, 25},  3,            78 },
            { new int[]{-7, -2, -19, -4},    -19,          -2 },   // all negative
            { new int[]{5, 9, 14, 21},       5,            21 },   // all positive
            { new int[]{42},                 42,           42 },   // single element
            { new int[]{8, 8, 8},            8,            8 },    // duplicates
            { new int[]{Integer.MIN_VALUE, 0, Integer.MAX_VALUE}, Integer.MIN_VALUE, Integer.MAX_VALUE },
        };
    }

    @Test(dataProvider = "arrays")
    public void findsMinAndMax(int[] input, int expectedMin, int expectedMax) {
        Assert.assertEquals(ArrayStats.min(input), expectedMin);
        Assert.assertEquals(ArrayStats.max(input), expectedMax);
    }

    @Test(dataProvider = "arrays")
    public void startingFromZeroIsABug(int[] input, int expectedMin, int expectedMax) {
        Assert.assertEquals(ArrayStats.minStartingFromZero(input), expectedMin);
        Assert.assertEquals(ArrayStats.maxStartingFromZero(input), expectedMax);
    }

    @Test(expectedExceptions = IllegalArgumentException.class)
    public void emptyArrayIsRejected() {
        ArrayStats.max(new int[0]);
    }

    @Test
    public void sortingToFindTheMaxChangesTheCallersArray() {
        int[] numbers = {12, 45, 78, 3, 25};
        Arrays.sort(numbers);
        int max = numbers[numbers.length - 1];
        Assert.assertEquals(max, 78);
        Assert.assertEquals(numbers, new int[]{3, 12, 25, 45, 78});   // original order is gone
    }

    @Test
    public void streamsAgreeWithTheLoop() {
        int[] numbers = {45, 12, 78, 3, 25};
        Assert.assertEquals(Arrays.stream(numbers).min().getAsInt(), ArrayStats.min(numbers));
        Assert.assertEquals(Arrays.stream(numbers).max().getAsInt(), ArrayStats.max(numbers));
    }
}

Result (15 checks):

PASS emptyArrayIsRejected -> IllegalArgumentException
PASS findsMinAndMax[[45, 12, 78, 3, 25], 3, 78]
PASS findsMinAndMax[[-7, -2, -19, -4], -19, -2]
PASS findsMinAndMax[[5, 9, 14, 21], 5, 21]
PASS findsMinAndMax[[42], 42, 42]
PASS findsMinAndMax[[8, 8, 8], 8, 8]
PASS findsMinAndMax[[-2147483648, 0, 2147483647], -2147483648, 2147483647]
PASS sortingToFindTheMaxChangesTheCallersArray
FAIL startingFromZeroIsABug[[45, 12, 78, 3, 25], 3, 78] : expected [3] but found [0]
FAIL startingFromZeroIsABug[[-7, -2, -19, -4], -19, -2] : expected [-2] but found [0]
FAIL startingFromZeroIsABug[[5, 9, 14, 21], 5, 21] : expected [5] but found [0]
FAIL startingFromZeroIsABug[[42], 42, 42] : expected [42] but found [0]
FAIL startingFromZeroIsABug[[8, 8, 8], 8, 8] : expected [8] but found [0]
PASS startingFromZeroIsABug[[-2147483648, 0, 2147483647], ...]
PASS streamsAgreeWithTheLoop
Total: 15, Passed: 10, Failed: 5

We compiled these tests with Java 21 and ran them with a minimal TestNG-compatible runner (the full TestNG library wasn't available in our environment); they use only standard TestNG annotations and Assert methods, so they run unchanged with mvn test in a TestNG project.

What the run shows:

  • The correct versions pass every case — negatives only, positives only, a single element, duplicates and the extreme int values.
  • The "start from 0" versions failed 5 of 6 data sets (the buggy min() returned 0 for every array whose values were all above 0). They only passed the one array that happened to contain 0 — which is exactly why this bug survives quick manual checks. Always start from numbers[0] (or Integer.MAX_VALUE / Integer.MIN_VALUE).
  • An empty array is rejected with a clear message instead of an ArrayIndexOutOfBoundsException or a silent default value.
  • Sorting to find the maximum works, but it rearranges the caller's array — a side effect a loop doesn't have.

Step through the loop and watch the running min/max change element by element in the Java Code Visualizer. More TestNG: TestNG Interview Questions.

From Real Projects

My automation work has been in Java — Selenium WebDriver scripts with TestNG in Eclipse — and I use OOP concepts such as classes and objects, method overloading, overriding and constructors in page classes and utilities. Small programs like this one are the building blocks of real framework code: looping through data, comparing expected and actual values, and handling edge cases. On Canolog, the many forms and screens across sales, inventory, finance and service are where keeping page details in POM classes and reusable steps in a business library paid off. Start from the first element, not from 0, or arrays of positive numbers will give the wrong answer.

📚 Official documentation: Selenium documentation · dev.java: Learn Java (Oracle)

🧩 Java Array Programs — 7 of 43

← Previous: Find Maximum Element in Array in Java

Next: Find Second Largest Element in an Array in Java →

See every program in the Java coding programs index.

Frequently Asked Questions

What's the time complexity of finding the minimum element in an array?

O(n).

A single pass through the array is sufficient and optimal.

Why not simply sort the array and take the first element?

Sorting requires O(n log n) time, whereas a linear scan only requires O(n).

Sorting is unnecessary when you only need the minimum value.

What if the array contains only negative numbers?

The linear scan works correctly regardless of whether the values are positive or negative, provided min is initialized with the first array element.

Can I find the minimum and maximum values in a single loop?

Yes.

Maintain two variables (min and max) and update both during the same traversal.

How do I find the minimum element in a List?

Use:

Collections.min(list);

for a List<Integer>.

What happens if the array is empty?

Accessing numbers[0] throws an ArrayIndexOutOfBoundsException.

Using Streams, .min() returns an empty OptionalInt, so handle it with .orElse() when appropriate.

Is there a built-in Java method to find the minimum directly?

Yes.

For primitive arrays:

Arrays.stream(arr).min();

For lists:

Collections.min(list);

How do I find the minimum element in a 2D array?

Traverse every row and every column while maintaining a running minimum.

Alternatively, flatten the 2D array using Streams and then call .min().

Conclusion

Finding the minimum element in an array is one of the most fundamental array operations in Java.

The linear scan remains the best solution because it provides:

  • O(n) time complexity

  • O(1) extra space

  • Excellent readability

  • Optimal interview performance

Whether you use a classic loop, an enhanced for loop, or Java Streams, every optimal solution examines each element exactly once, making the algorithm both simple and highly efficient.