How to Find the Maximum Element in an Array in Java
Finding the largest value in an array is one of the most frequently asked questions in Java coding interviews — not because it's hard, but because it tests whether you reach for the efficient O(n) solution or default to unnecessarily sorting the entire array first.
This guide covers every practical approach, from the fundamental linear scan to modern one-liners with streams.
Problem Statement
Given an array such as {12, 45, 78, 3, 25}, the task is to identify the single largest value — here, 78.
The most efficient solution visits each element exactly once, comparing it against the largest value found so far.
Method 1: Linear Scan (Classic Loop) – The Optimal Approach
int[] numbers = {12, 45, 78, 3, 25};
int max = numbers[0];
for (int i = 1; i < numbers.length; i++) {
if (numbers[i] > max) {
max = numbers[i];
}
}
System.out.println("Maximum element: " + max);
This is the textbook-optimal solution:
-
Time Complexity: O(n)
-
Space Complexity: O(1)
-
Number of Passes: One
The loop starts at index 1, not 0, because the first element is already assigned as the initial max.
Comparing it with itself would be redundant.
Method 2: Enhanced For Loop
int max = numbers[0];
for (int num : numbers) {
if (num > max) {
max = num;
}
}
Functionally identical, but with slightly cleaner syntax.
This is a common upgrade from the indexed loop when the array index isn't required.
Method 3: Arrays.sort() Approach (Not Recommended for This Purpose)
import java.util.Arrays;
Arrays.sort(numbers);
int max = numbers[numbers.length - 1];
Side effect: Arrays.sort() reorders the original array in place — if the caller still needs the original order, sort a copy (int[] sorted = numbers.clone();). It's also O(n log n), slower than the O(n) loop.
This works, but it's unnecessarily inefficient.
Sorting requires O(n log n) time, while a simple linear scan only needs O(n).
This approach is worth knowing conceptually (and is a common "wrong but working" interview answer), but should be avoided when the only goal is finding the maximum element.
Method 4: Java Streams
import java.util.Arrays;
int max = Arrays.stream(numbers)
.max()
.getAsInt();
This is concise and modern.
Internally, it still performs an O(n) linear scan.
Streams don't improve the algorithm—they simply provide cleaner syntax.
If the array might be empty, use:
int max = Arrays.stream(numbers)
.max()
.orElse(Integer.MIN_VALUE);
to avoid NoSuchElementException.
Step-by-Step Explanation
Initialize max
Set max to the first element.
int max = numbers[0];
This provides a valid starting reference.
Loop from index 1
Since the first element is already stored in max, begin comparing from index 1.
Compare each element
if (numbers[i] > max) {
max = numbers[i];
}
Whenever a larger value is found, update max.
Final result
After the loop finishes, max contains the largest value in the array.
Internal Working (Memory View)
For the array:
{12, 45, 78, 3, 25}
Execution looks like this:
Start:
max = 12
i = 1
45 > 12
max = 45
i = 2
78 > 45
max = 78
i = 3
3 > 78 ?
No
i = 4
25 > 78 ?
No
Final:
max = 78
Only one comparison per element is needed.
The max variable is stored on the stack and updated in place without allocating additional memory.
Real-Life Analogy
Imagine judging a height competition.
You assume the first contestant is the tallest.
As each new contestant steps forward, you compare their height with the current tallest person.
If someone taller appears, you update your record.
By the end of the competition, you've found the tallest contestant without ever needing to arrange everyone from shortest to tallest.
Best Practices
-
Always use the linear scan (O(n)) approach when you only need the maximum element.
-
Avoid sorting unless you also need the array sorted for another purpose.
-
Handle empty arrays before accessing
numbers[0]. -
Use
Arrays.stream(arr).max().orElse(Integer.MIN_VALUE)for concise and safe stream-based code. -
For object arrays, use
Collections.max()with aComparator, or streams withComparator.naturalOrder().
Common Mistakes
Sorting just to find the maximum
Sorting increases the time complexity from O(n) to O(n log n) unnecessarily.
Initializing max to 0
int max = 0;
This fails when every number in the array is negative.
Always initialize with the first array element instead.
Ignoring empty arrays
Trying to access:
numbers[0]
on an empty array throws ArrayIndexOutOfBoundsException.
Using >= instead of >
While this still finds the maximum correctly, using > better reflects the intended comparison logic and is generally preferred during interviews.
Expert Tips
-
Initializing
maxwithInteger.MIN_VALUEis another valid approach, but using the first array element is usually clearer and avoids unnecessary assumptions. -
For a
List<Integer>, use:
Collections.max(list);
-
For custom objects, use a comparator.
Collections.max(
employees,
Comparator.comparing(Employee::getSalary)
);
The same pattern also works with Java Streams.
Comparison Table
| Method | Time Complexity | Space Complexity | Recommended? |
|---|---|---|---|
| Linear scan | O(n) | O(1) | ✅ Yes – Optimal |
| Enhanced for loop | O(n) | O(1) | ✅ Yes – Cleaner syntax |
| Arrays.sort() + last element | O(n log n) | O(1) or O(n) depending on implementation | ❌ Not recommended |
Streams .max() |
O(n) | O(1) | ✅ Yes – Concise and modern |
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
intvalues. - The "start from 0" versions failed 5 of 6 data sets (the buggy max() returned 0 for arrays whose values were all negative, and the buggy min() returned 0 whenever all values were positive). 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](orInteger.MAX_VALUE/Integer.MIN_VALUE). - An empty array is rejected with a clear message instead of an
ArrayIndexOutOfBoundsExceptionor 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. Arrays of only negative numbers are the edge case that catches most versions.
📚 Official documentation: Selenium documentation · dev.java: Learn Java (Oracle)
← Previous: Find Average of Array Elements in Java
Next: Find Minimum Element in an Array in Java →
See every program in the Java coding programs index.
Frequently Asked Questions
What is the most efficient way to find the maximum element in a Java array?
A single linear scan (O(n)) that keeps track of the largest value seen so far.
No sorting is required.
Why does the loop start from index 1 instead of 0?
Because numbers[0] is already used as the initial maximum.
Comparing it with itself would be unnecessary.
What happens if the array is empty?
Accessing numbers[0] throws an ArrayIndexOutOfBoundsException.
Always check:
numbers.length > 0
before processing.
Is using Arrays.sort() to find the maximum a good practice?
No.
Although it works, sorting is O(n log n) while a linear scan is only O(n).
How do I find the maximum in an array of Integer objects instead of int?
Use:
Collections.max(Arrays.asList(integerArray));
or use Streams with:
.max(Comparator.naturalOrder())
Can I find both the maximum and minimum in a single pass?
Yes.
Maintain two variables (max and min) and update both during the same traversal.
This still runs in O(n) time.
What's the difference between max() with streams and a manual loop?
They are algorithmically identical.
Streams provide cleaner, more declarative syntax, while a manual loop offers slightly more control.
How do I find the maximum element in a 2D array?
Traverse every row and every column while maintaining a running maximum.
Alternatively, flatten the array using streams and call .max().
Conclusion
Finding the maximum element in an array is a classic Java problem that demonstrates efficient array traversal.
The recommended solution is a single linear scan, which provides:
-
O(n) time complexity
-
O(1) extra space
-
Excellent readability
-
Optimal interview performance
Whether you choose a traditional loop, an enhanced for loop, or Java Streams, all optimal approaches examine each element exactly once, making them both efficient and easy to understand.