Second Highest Salary Using Streams
Java coding interview problem for Java 8 Streams: Second Highest Salary Using Streams.
Finding the second highest salary is one of the most frequently asked Java Stream API interview problems.
This problem looks simple but tests several important concepts:
- Sorting
- Stream operations
- Comparator
- distinct values
- Object comparison
- Handling duplicate salaries
What is Second Highest Salary?
Given a list of employees, find the employee with the second highest salary.
Example:
Employees:
John 90000
Alice 120000
Bob 75000
David 100000
Salary ranking:
120000
100000
90000
75000
Second highest salary:
100000
Employee:
David
Understanding Ranking Problems
Finding maximum:
Highest Salary
requires:
1 comparison condition
Finding second maximum requires:
Track two values
Example:
Highest
Second Highest
During traversal:
Current Salary
↓
Compare with Highest
↓
Update ranking
Difference Between Highest and Second Highest
Example:
[50000,80000,100000]
Highest:
100000
Second Highest:
80000
But:
[50000,100000,100000]
creates a question:
Should second highest be:
100000
or:
50000
?
Most interview problems expect:
Second DISTINCT highest salary
Duplicate Salary Concept
Example:
Employees:
John 120000
Alice 120000
Bob 90000
Unique salaries:
120000
90000
Second highest salary:
90000
Therefore:
We usually apply:
distinct()
before selecting second value.
Employee Object Design
We will use:
Employee
|
|-- id
|
|-- name
|
|-- department
|
|-- salary
Employee Class
class Employee {
private int id;
private String name;
private String department;
private double salary;
public Employee(
int id,
String name,
String department,
double salary) {
this.id = id;
this.name = name;
this.department = department;
this.salary = salary;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getDepartment() {
return department;
}
public double getSalary() {
return salary;
}
@Override
public String toString() {
return name +
" - " +
salary;
}
}
Why This Problem is Asked in Interviews?
This problem evaluates:
1. Stream API Knowledge
Can you use:
sorted()
distinct()
skip()
findFirst()
?
2. Comparator Understanding
Can you sort objects by:
salary
?
3. Edge Case Handling
What happens when:
- Only one employee exists?
- Duplicate salaries exist?
- No second highest salary exists?
4. Algorithm Optimization
Can you compare:
Sorting approach
vs
Single pass approach
?
Real-World Applications
HR Systems
Find:
Second highest paid employee
for salary analysis.
Finance Applications
Find:
Second largest transaction
E-Commerce
Find:
Second highest product price
Analytics Systems
Find:
Second highest metric value
Problem Statement
Given a list of employees, find the employee having the second highest salary using Java Streams.
Input Example
[
John IT 90000,
Alice HR 120000,
Bob Finance 75000,
David IT 100000
]
Expected Output
David - 100000
Finding Second Maximum Concept
Traditional approach:
Maintain:
highestSalary
secondHighestSalary
Example:
Input:
90000
120000
75000
100000
Start:
Highest = 0
Second = 0
Read:
90000
Update:
Highest = 90000
Read:
120000
Update:
Highest = 120000
Second = 90000
Read:
75000
No change.
Read:
100000
Update:
Second = 100000
Final:
Highest = 120000
Second = 100000
Approach 1 — Sorting Employees by Salary
The simplest solution:
- Sort employees by salary descending.
- Skip first employee.
- Take next employee.
Algorithm
Employee List
↓
Sort Salary Descending
↓
Skip Highest
↓
Get Next Employee
Java Program — Sorting Approach
import java.util.*;
public class SecondHighestSalary {
public static Employee findSecondHighest(
List<Employee> employees) {
return employees.stream()
.sorted(
Comparator
.comparing(
Employee::getSalary
)
.reversed()
)
.skip(1)
.findFirst()
.orElse(null);
}
}
Dry Run
Input:
John 90000
Alice 120000
Bob 75000
David 100000
Sort descending:
Alice 120000
David 100000
John 90000
Bob 75000
Skip first:
Alice
Next:
David 100000
Result:
David
Problem With Duplicate Salary
Input:
Alice 120000
Bob 120000
David 100000
Sorted:
Alice 120000
Bob 120000
David 100000
skip(1):
returns:
Bob 120000
But expected:
David 100000
because salary should be distinct.
Need:
distinct salary handling
Approach 2 — Using Stream distinct()
Instead of sorting employees directly:
First extract salaries.
Flow:
Employees
↓
Salary values
↓
Remove duplicates
↓
Sort descending
↓
Second value
Java Program — Second Highest Salary Value
import java.util.*;
public class SecondHighestSalaryValue {
public static Double findSecondHighestSalary(
List<Employee> employees) {
return employees.stream()
.map(
Employee::getSalary
)
.distinct()
.sorted(
Comparator.reverseOrder()
)
.skip(1)
.findFirst()
.orElse(null);
}
}
Step-by-Step Explanation
Employees:
John 90000
Alice 120000
Bob 120000
David 100000
Extract salary:
90000
120000
120000
100000
distinct():
90000
120000
100000
Sort descending:
120000
100000
90000
skip first:
120000
Result:
100000
Complexity Analysis
Sorting:
O(n log n)
Stream processing:
O(n)
Total:
O(n log n)
Space:
O(n)
Advantages
- Clean Stream solution.
- Handles duplicate salaries.
- Easy to understand.
- Interview friendly.
Drawbacks
- Requires sorting.
- Extra memory.
- Not optimal for huge datasets.
Finding Second Highest Employee Object Using Streams
The previous approach finds only the salary value.
Many interviews ask:
Find the employee object having the second highest salary.
Example:
Employees:
John 90000
Alice 120000
Bob 75000
David 100000
Expected:
David 100000
Stream Pipeline
Employees
↓
Sort by Salary Descending
↓
Remove duplicate salaries
↓
Skip Highest
↓
Find Employee
Java Program — Second Highest Employee
import java.util.*;
public class SecondHighestEmployee {
public static Employee findSecondHighest(
List<Employee> employees) {
return employees.stream()
.sorted(
Comparator
.comparing(
Employee::getSalary
)
.reversed()
)
.filter(
employee ->
employees.stream()
.filter(
e ->
e.getSalary()
==
employee.getSalary()
)
.count()
>= 1
)
.skip(1)
.findFirst()
.orElse(null);
}
}
Better Approach Using Salary Set
A cleaner approach:
- Find second highest salary.
- Find employee with that salary.
Step 1 — Find Second Highest Salary
double secondHighestSalary =
employees.stream()
.map(
Employee::getSalary
)
.distinct()
.sorted(
Comparator.reverseOrder()
)
.skip(1)
.findFirst()
.orElse(0);
Step 2 — Find Employee
Employee result =
employees.stream()
.filter(
employee ->
employee.getSalary()
==
secondHighestSalary
)
.findFirst()
.orElse(null);
Why Separate Steps?
It separates responsibilities:
Find Ranking
↓
Find Object
This is easier to debug and maintain.
Using Comparator Without Sorting
Sorting is:
O(n log n)
For only finding second highest:
we can use:
Single Traversal
Single Pass Algorithm
Maintain:
highestSalary
secondHighestSalary
Java Program — O(n) Solution
public class SecondHighestSinglePass {
public static Employee findSecondHighest(
List<Employee> employees) {
Employee highest = null;
Employee secondHighest = null;
for(Employee employee : employees) {
if(highest == null ||
employee.getSalary()
>
highest.getSalary()) {
secondHighest = highest;
highest = employee;
}
else if(
(secondHighest == null ||
employee.getSalary()
>
secondHighest.getSalary())
&&
employee.getSalary()
<
highest.getSalary()
) {
secondHighest = employee;
}
}
return secondHighest;
}
}
Dry Run — Single Pass
Input:
John 90000
Alice 120000
Bob 75000
David 100000
Initial:
Highest = null
Second = null
Read John:
90000
Update:
Highest = John
Read Alice:
120000
Update:
Highest = Alice
Second = John
Read Bob:
75000
No change.
Read David:
100000
Compare:
100000 < 120000
Update:
Second = David
Final:
Highest = Alice
Second = David
Complexity Analysis
Each employee is processed once.
Time:
O(n)
Space:
O(1)
PriorityQueue Approach
For large datasets, another approach is:
Min Heap
Maintain:
Top 2 salaries
Example:
Employees:
90000
120000
75000
100000
Heap size:
2
Final heap:
100000
120000
Java Program
import java.util.*;
public class SecondHighestUsingHeap {
public static Employee findSecondHighest(
List<Employee> employees) {
PriorityQueue<Employee> heap =
new PriorityQueue<>(
Comparator.comparing(
Employee::getSalary
)
);
for(Employee employee :
employees) {
heap.offer(employee);
if(heap.size() > 2) {
heap.poll();
}
}
return heap.peek();
}
}
Complexity
For each insertion:
O(log k)
where:
k = 2
Total:
O(n log k)
Since:
k = 2
approximately:
O(n)
Space:
O(k)
Finding Second Highest Salary Per Department
Another very common enterprise question:
Find second highest paid employee in each department.
Example:
Input:
John IT 90000
Bob IT 120000
Mike IT 100000
Alice HR 80000
David HR 100000
Output:
IT → Mike 100000
HR → Alice 80000
Approach
Group Employees
↓
Sort Each Group
↓
Skip First
↓
Return Second
Java Program
import java.util.*;
import java.util.stream.Collectors;
Map<String,Employee> result =
employees.stream()
.collect(
Collectors.groupingBy(
Employee::getDepartment,
Collectors.collectingAndThen(
Collectors.toList(),
list -> list.stream()
.sorted(
Comparator
.comparing(
Employee::getSalary
)
.reversed()
)
.skip(1)
.findFirst()
.orElse(null)
)
)
);
Explanation
First group:
IT
[
John 90000,
Bob 120000,
Mike 100000
]
Sort:
120000
100000
90000
Skip first:
100000
Result:
Mike
Sorting vs Stream vs Heap Comparison
| Approach | Time | Space | Best Use |
|---|---|---|---|
| Sorting | O(n log n) | O(n) | Simple solutions |
| Stream sorted() | O(n log n) | O(n) | Modern Java |
| Single Pass | O(n) | O(1) | Best performance |
| PriorityQueue | O(n log k) | O(k) | Large datasets |
Handling Null Values
Production data may contain:
Employee = null
Salary = null
Ignore Null Employees
employees.stream()
.filter(
Objects::nonNull
)
Handle Null Salary
Comparator<Employee> comparator =
Comparator.comparing(
Employee::getSalary,
Comparator.nullsLast(
Double::compare
)
);
Comparable vs Comparator
Comparable
Used for natural ordering.
Example:
Employee default sorting
Comparator
Used for custom sorting.
Example:
Salary ranking
Common Interview Mistakes
Mistake 1
Using:
skip(1)
without:
distinct salary
Problem:
120000
120000
100000
returns wrong result.
Mistake 2
Not handling fewer than two employees.
Example:
[John]
No second highest exists.
Mistake 3
Sorting entire list unnecessarily.
For maximum performance:
Use:
Single Pass
Mistake 4
Ignoring duplicate salaries.
Clarify:
Second employee?
or
Second distinct salary?
Edge Cases
| Case | Handling |
|---|---|
| Empty list | Return null/Optional |
| One employee | No second salary |
| Same salary for all | No second distinct salary |
| Duplicate salaries | Use distinct() |
| Null values | Filter/handle |
Interview Follow-up Questions
Q1. Find highest salary employee.
Q2. Find second highest salary.
Q3. Find third highest salary.
Q4. Find Nth highest salary.
Q5. Find second highest salary by department.
Q6. Difference between sorting and heap.
Q7. How to solve without sorting?
Related Java Collection Problems
- Find Employees With Highest Salary
- Sort Employees by Salary
- Group Employees by Department
- Custom Comparator Examples
- Convert List to Map
- Top K Frequent Elements
Key Takeaways
Second highest salary follows:
Employee List
↓
Find Ranking
↓
Handle Duplicates
↓
Return Employee
Recommended solutions:
Interview Friendly
Use:
Stream
+
distinct()
+
sorted()
+
skip()
Production Performance
Use:
Single Pass O(n)
Large Data
Use:
PriorityQueue
Complexities:
Stream sorting:
O(n log n)
Single pass:
O(n)
Heap:
O(n log k)
Frequently Asked Interview Questions
Q1. Why use distinct()?
To ignore duplicate salaries.
Q2. Why not simply skip(1)?
Because duplicate highest salaries may exist.
Q3. What is the optimal solution?
Single traversal with two variables.
Q4. How to find second highest per department?
Use:
groupingBy()
+
sorting/max logic
Interview Tip
When asked:
"Find second highest salary using Streams."
Explain:
- Extract salary values.
- Remove duplicates using
distinct(). - Sort descending.
- Skip highest salary.
- Get next value.
- For object retrieval, filter employees by salary.
For senior Java interviews, discuss:
- Stream pipeline design.
- Comparator usage.
- Duplicate handling.
- Complexity trade-offs.
- Single-pass optimization.
This demonstrates strong understanding of Java Streams, Collections, and real-world ranking problems.