Find Max and Min Using Streams
Java coding interview problem for Java 8 Streams: Find Max and Min Using Streams.
Finding maximum and minimum values is one of the most common Java coding interview problems.
Examples:
- Find the largest number in a list.
- Find the smallest number in a list.
- Find highest salary employee.
- Find lowest priced product.
This problem introduces:
- Stream API
max()min()- Comparator
- Optional
- Reduction operations
What are Maximum and Minimum Problems?
Maximum and minimum problems find the extreme values from a collection.
Example:
Input:
[10,50,20,90,30]
Maximum:
90
Minimum:
10
Understanding Aggregation Operations
Aggregation means combining multiple values into a single result.
Examples:
List Numbers
↓
Calculate
↓
Single Value
Common aggregation operations:
| Operation | Result |
|---|---|
| sum() | Total value |
| max() | Largest value |
| min() | Smallest value |
| count() | Number of elements |
| average() | Average value |
Why Max and Min Problems Are Important?
These problems test:
1. Stream API Knowledge
Understanding:
stream()
max()
min()
2. Comparator Usage
Finding maximum based on:
- Salary
- Age
- Price
- Date
3. Optional Handling
Streams return:
Optional<T>
because collections can be empty.
Real-World Applications
Banking Systems
Find:
Highest transaction amount
Lowest transaction amount
Employee Management
Find:
Highest paid employee
Lowest paid employee
E-Commerce
Find:
Most expensive product
Cheapest product
Monitoring Systems
Find:
Maximum response time
Minimum response time
Problem Statement
Given a list of integers, find:
- Maximum number
- Minimum number
using Java Streams.
Example 1
Input:
[10,20,5,40,30]
Output:
Maximum = 40
Minimum = 5
Example 2
Input:
[100,50,200,25]
Output:
Maximum = 200
Minimum = 25
Java Stream API Overview
Streams provide a functional approach for processing collections.
Stream flow:
Collection
↓
Stream
↓
Intermediate Operations
↓
Terminal Operation
↓
Result
Example:
numbers.stream()
.max();
Stream Pipeline Concept
Example:
numbers.stream()
.max(
Comparator.naturalOrder()
);
Flow:
List<Integer>
↓
stream()
↓
Compare Elements
↓
Find Maximum
↓
Optional<Integer>
Approach 1 — Traditional Loop Approach
Before Streams, loops were commonly used.
Algorithm
- Initialize max value.
- Traverse list.
- Compare every element.
- Update maximum.
Java Program — Find Maximum
import java.util.*;
public class FindMaximum {
public static int findMax(
List<Integer> numbers) {
int max = numbers.get(0);
for(Integer number : numbers) {
if(number > max) {
max = number;
}
}
return max;
}
public static void main(String[] args) {
List<Integer> numbers =
Arrays.asList(
10,
20,
5,
40,
30
);
System.out.println(
findMax(numbers)
);
}
}
Output
40
Dry Run — Maximum
Input:
[10,20,5,40,30]
Initial:
max = 10
Compare:
20 > 10
Update:
max = 20
Compare:
5 > 20
No change.
Compare:
40 > 20
Update:
max = 40
Compare:
30 > 40
No change.
Final:
max = 40
Java Program — Find Minimum
public static int findMin(
List<Integer> numbers) {
int min = numbers.get(0);
for(Integer number : numbers) {
if(number < min) {
min = number;
}
}
return min;
}
Complexity Analysis — Loop Approach
Let:
n = number of elements
Traversal:
O(n)
Space:
O(1)
Approach 2 — Using Stream max()
Java Stream provides:
max()
to find maximum element.
Syntax:
stream.max(comparator)
Example:
Optional<Integer> max =
numbers.stream()
.max(
Comparator.naturalOrder()
);
Java Program — Maximum Using Streams
import java.util.*;
public class MaximumUsingStreams {
public static Integer findMax(
List<Integer> numbers) {
return numbers.stream()
.max(
Comparator.naturalOrder()
)
.orElse(null);
}
public static void main(String[] args) {
List<Integer> numbers =
Arrays.asList(
10,
20,
5,
40,
30
);
System.out.println(
findMax(numbers)
);
}
}
Output
40
Understanding Comparator.naturalOrder()
Natural ordering means:
Ascending order
Example:
Numbers:
10,20,5,40
Comparison:
40 is greater
For maximum:
Comparator.naturalOrder()
is used.
For minimum:
Comparator.reverseOrder()
or:
min()
can be used.
Java Program — Minimum Using Streams
public static Integer findMin(
List<Integer> numbers) {
return numbers.stream()
.min(
Comparator.naturalOrder()
)
.orElse(null);
}
Output
5
Stream Pipeline Explanation
Input:
10,20,5,40,30
Stream:
10
20
5
40
30
max():
Compare:
10 vs 20
20 vs 5
20 vs 40
40 vs 30
Result:
40
Using Primitive Streams
For numbers, Java provides:
IntStream
LongStream
DoubleStream
Example:
int max =
numbers.stream()
.mapToInt(
Integer::intValue
)
.max()
.orElse(0);
Advantages:
- No boxing/unboxing
- Better performance
- Built for primitive values
Finding Maximum With reduce()
Another Stream approach:
Optional<Integer> max =
numbers.stream()
.reduce(
Integer::max
);
How it works:
10,20,5,40,30
↓
20
↓
20
↓
40
↓
40
Result:
40
Handling Empty Collections
Important interview scenario.
Input:
[]
Problem:
No maximum exists.
Stream returns:
Optional<Integer>
Example:
Optional<Integer> result =
numbers.stream()
.max(
Comparator.naturalOrder()
);
Check:
result.isPresent()
Or:
.orElse(0)
Handling Null Values
Input:
[10,20,null,40]
Problem:
Comparator cannot compare null.
Solution:
Filter null values.
numbers.stream()
.filter(
Objects::nonNull
)
.max(
Comparator.naturalOrder()
);
Finding Highest Salary Employee
Common enterprise example.
Employee:
John 90000
Alice 150000
Bob 70000
Requirement:
Find:
Highest Salary Employee
Code:
Employee highest =
employees.stream()
.max(
Comparator.comparing(
Employee::getSalary
)
)
.orElse(null);
Finding Lowest Salary Employee
Employee lowest =
employees.stream()
.min(
Comparator.comparing(
Employee::getSalary
)
)
.orElse(null);
Deep Dive Into Stream max() and min()
Java Stream API provides:
max()
and
min()
for finding extreme values from a stream.
max() Method
Syntax:
Optional<T> max(
Comparator<? super T> comparator
)
Purpose:
Returns:
Largest element
based on the provided comparator.
Example:
Optional<Integer> result =
numbers.stream()
.max(
Comparator.naturalOrder()
);
Input:
[10,50,20,90]
Output:
90
min() Method
Syntax:
Optional<T> min(
Comparator<? super T> comparator
)
Purpose:
Returns:
Smallest element
Example:
Optional<Integer> result =
numbers.stream()
.min(
Comparator.naturalOrder()
);
Input:
[10,50,20,90]
Output:
10
Understanding Optional Return Type
Why does Stream return:
Optional<T>
instead of:
T
?
Because the stream may contain no elements.
Example:
List<Integer> numbers =
new ArrayList<>();
Question:
What is maximum?
Answer:
No value exists
Therefore:
Optional
safely represents:
Value exists
or
No value
Optional Handling Examples
Using orElse()
Integer max =
numbers.stream()
.max(
Comparator.naturalOrder()
)
.orElse(0);
If empty:
Returns 0
Using ifPresent()
numbers.stream()
.max(
Comparator.naturalOrder()
)
.ifPresent(
value ->
System.out.println(value)
);
Using orElseThrow()
Integer max =
numbers.stream()
.max(
Comparator.naturalOrder()
)
.orElseThrow();
Comparator.comparing() Usage
For objects, Java cannot directly compare.
Example:
Employee:
name
salary
Need:
Compare salary field
Use:
Comparator.comparing()
Employee Example
class Employee {
private String name;
private double salary;
public Employee(
String name,
double salary) {
this.name = name;
this.salary = salary;
}
public String getName(){
return name;
}
public double getSalary(){
return salary;
}
public String toString(){
return name;
}
}
Find Highest Salary Employee
Employee highest =
employees.stream()
.max(
Comparator.comparing(
Employee::getSalary
)
)
.orElse(null);
Input:
John 90000
Alice 150000
Bob 70000
Comparison:
90000
vs
150000
vs
70000
Result:
Alice
Find Lowest Salary Employee
Employee lowest =
employees.stream()
.min(
Comparator.comparing(
Employee::getSalary
)
)
.orElse(null);
Result:
Bob
Finding Second Highest Value
Common interview problem:
Input:
[10,50,20,90,30]
Expected:
50
Approach:
Sort Descending
↓
Skip First
↓
Get Next
Java:
Integer secondHighest =
numbers.stream()
.distinct()
.sorted(
Comparator.reverseOrder()
)
.skip(1)
.findFirst()
.orElse(null);
Finding Second Lowest Value
Integer secondLowest =
numbers.stream()
.distinct()
.sorted()
.skip(1)
.findFirst()
.orElse(null);
Finding Max/Min With Multiple Fields
Sometimes one field is not enough.
Example:
Sort employees by:
- Salary
- Name
Comparator:
Comparator<Employee> comparator =
Comparator
.comparing(
Employee::getSalary
)
.thenComparing(
Employee::getName
);
Find maximum:
Employee employee =
employees.stream()
.max(comparator)
.orElse(null);
Finding Max Date
Example:
Orders:
Order Date
Find latest order:
Order latestOrder =
orders.stream()
.max(
Comparator.comparing(
Order::getCreatedDate
)
)
.orElse(null);
Finding Minimum Price Product
Product:
Laptop 1200
Phone 800
Tablet 500
Code:
Product cheapest =
products.stream()
.min(
Comparator.comparing(
Product::getPrice
)
)
.orElse(null);
Result:
Tablet
Using reduce() for Maximum
Streams support reduction operations.
Example:
Optional<Integer> max =
numbers.stream()
.reduce(
Integer::max
);
Internal working:
10,50
↓
50
50,20
↓
50
50,90
↓
90
Result:
90
max() vs reduce()
| Feature | max() | reduce() |
|---|---|---|
| Purpose | Find extreme value | General aggregation |
| Readability | Better | More flexible |
| Performance | Optimized | Depends on operation |
| Interview usage | Preferred | Advanced cases |
Primitive Streams
Java provides specialized streams:
IntStream
LongStream
DoubleStream
Benefits:
- No boxing
- Better performance
- Built-in operations
Example — IntStream max()
int max =
numbers.stream()
.mapToInt(
Integer::intValue
)
.max()
.orElse(0);
Example — Average
double average =
numbers.stream()
.mapToInt(
Integer::intValue
)
.average()
.orElse(0);
max() vs sorted()
Both can find maximum.
sorted()
numbers.stream()
.sorted(
Comparator.reverseOrder()
)
.findFirst();
It performs:
Complete Sorting
Complexity:
O(n log n)
max()
numbers.stream()
.max(
Comparator.naturalOrder()
);
Only finds:
Single maximum
Complexity:
O(n)
Comparison Table
| Approach | Time Complexity | Best Use |
|---|---|---|
| max() | O(n) | Single maximum |
| min() | O(n) | Single minimum |
| sorted() | O(n log n) | Ranking problems |
| PriorityQueue | O(n log k) | Top K problems |
Stream vs Loop Comparison
| Feature | Loop | max()/min() |
|---|---|---|
| Code | More | Compact |
| Readability | Good | Excellent |
| Performance | O(n) | O(n) |
| Functional style | No | Yes |
| Object handling | Manual | Comparator |
Comparator Internal Working
Comparator defines:
How two objects are compared
Example:
Employee::getSalary
creates comparison:
Employee A salary
vs
Employee B salary
Internally:
Object
↓
Extract Field
↓
Compare Values
↓
Return Result
Parallel Stream Considerations
Example:
numbers.parallelStream()
.max(
Comparator.naturalOrder()
);
Parallel streams:
- Split data
- Process chunks
- Combine results
For large datasets:
May improve performance.
For small lists:
Normal:
stream()
is usually faster.
Common Interview Mistakes
Mistake 1
Using sorted() for maximum.
Wrong:
sorted()
.findFirst()
Better:
max()
Mistake 2
Ignoring Optional.
Wrong:
.get()
without checking.
Mistake 3
Wrong comparator direction.
Example:
Comparator.reverseOrder()
with max() can produce unexpected results.
Mistake 4
Not handling null values.
Use:
.filter(
Objects::nonNull
)
Edge Cases
| Case | Handling |
|---|---|
| Empty list | Use Optional |
| Single element | Returns that element |
| Duplicate values | Handled normally |
| Null values | Filter first |
| Objects | Use Comparator |
Interview Follow-up Questions
Q1. Difference between max() and sorted()?
Q2. Why does max() return Optional?
Q3. Find highest salary employee.
Q4. Find second highest salary.
Q5. Find max by multiple fields.
Q6. How does Comparator work?
Q7. When to use primitive streams?
Related Java Collection Problems
- Second Highest Salary Using Streams
- Top N Highest Numbers
- Sort Employees by Salary
- Custom Comparator Examples
- Find Employees With Highest Salary
- Convert List to Map Using Streams
Key Takeaways
Maximum and minimum pattern:
Collection
↓
Stream
↓
Comparator
↓
max()/min()
↓
Optional Result
Use:
Single Maximum
max()
Use:
Single Minimum
min()
Use:
Ranking
sorted()
Use:
Large Top K Problems
PriorityQueue
Complexity:
max():
O(n)
min():
O(n)
sorted():
O(n log n)
Frequently Asked Interview Questions
Q1. Why does max() need Comparator?
Because Stream does not know how objects should be compared.
Q2. Can max() work with custom objects?
Yes, using:
Comparator.comparing()
Q3. Which is faster: max() or sorted()?
max() because it performs a single traversal.
Q4. Why use Optional?
To safely handle empty streams.
Interview Tip
When asked:
"Find maximum and minimum using Java Streams."
Explain:
- Use
max()andmin()terminal operations. - Provide Comparator for custom objects.
- Handle Optional safely.
- Use primitive streams for numeric performance.
- Avoid sorting when only one extreme value is required.
For senior Java interviews, discuss:
- Comparator design.
- Optional handling.
- Reduction operations.
- Stream performance.
- Parallel processing.
This demonstrates strong understanding of Java Streams, Collections, and functional programming patterns.