Back to Stream Practice: Employee Analysis
Q39Question 39 of 43

Find the department that has the highest average salary

Key Concepts
  • groupingBy(dept, averagingDouble(salary)) produces Map<String, Double> of avg salary per department
  • entrySet().stream().max(comparingByValue()) finds the department with the highest average
  • This is the same two-step pattern as 'department with most employees' but with averaging instead of counting
  • For ties, find the max value first, then filter all entries matching it
  • averagingDouble loses precision for BigDecimal; use exact arithmetic for audited figures
  • collectingAndThen can combine both steps into one collect call

Definition

Group by department with averagingDouble(salary) as the downstream, then stream the entrySet and find max by value to identify the department with the highest average salary.
  • Step 1: groupingBy(department, averagingDouble(salary)) produces Map.
  • Step 2: entrySet().stream().max(comparingByValue()) returns the department with the highest average.
  • Same pattern as finding the department with the most employees, but averaging instead of counting.
  • Precision: averagingDouble has floating-point drift; for audited reports use BigDecimal arithmetic.

The National Bank of India compensation committee asks: 'Which department pays the most on average?' First compute the average salary per department, then scan the averages for the highest one.

Understanding the Concepts

What does this question ask?

This is the two-step aggregate-then-max pattern. Step 1 computes averages per department. Step 2 finds the department with the highest average.

How do you find the department with the highest average salary?

JAVA
package com.bank.hr;

import java.util.*;
import java.util.stream.Collectors;

public class HighestAvgSalaryDept {
    public static void main(String[] args) {
        List<Employee> employees = Employee.getSampleEmployees();

        Map<String, Double> avgByDept = employees.stream()
            .collect(Collectors.groupingBy(
                Employee::getDepartment,
                Collectors.averagingDouble(
                    e -> e.getSalary().doubleValue())));

        Optional<Map.Entry<String, Double>> highest = avgByDept.entrySet()
            .stream()
            .max(Map.Entry.comparingByValue());

        highest.ifPresent(e ->
            System.out.printf("Highest avg salary: %s (Rs.%.2f)%n",
                e.getKey(), e.getValue()));
    }
}
TEXT
Highest avg salary: TRADING (Rs.1500000.00)

How do you handle ties?

JAVA
double maxAvg = avgByDept.values().stream()
    .mapToDouble(Double::doubleValue).max().orElse(0);

List<String> tied = avgByDept.entrySet().stream()
    .filter(e -> Double.compare(e.getValue(), maxAvg) == 0)
    .map(Map.Entry::getKey)
    .toList();

What are common mistakes?

Mistake: using averagingDouble directly on BigDecimal without conversion.

JAVA
// WRONG: compile error
Double wrong = employees.stream()
    .collect(Collectors.averagingDouble(Employee::getSalary));

// CORRECT: convert to double
Double correct = employees.stream()
    .collect(Collectors.averagingDouble(
        e -> e.getSalary().doubleValue()));

How do you rank all departments by average salary?

JAVA
LinkedHashMap<String, Double> ranked = avgByDept.entrySet().stream()
    .sorted(Map.Entry.<String, Double>comparingByValue().reversed())
    .collect(Collectors.toMap(
        Map.Entry::getKey, Map.Entry::getValue,
        (a, b) -> a, LinkedHashMap::new));

ranked.forEach((dept, avg) ->
    System.out.printf("%s: Rs.%.2f%n", dept, avg));

What about using exact BigDecimal arithmetic?

JAVA
Map<String, BigDecimal> exactAvg = employees.stream()
    .collect(Collectors.groupingBy(
        Employee::getDepartment,
        Collectors.collectingAndThen(
            Collectors.toList(),
            list -> {
                BigDecimal sum = list.stream()
                    .map(Employee::getSalary)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
                return sum.divide(
                    BigDecimal.valueOf(list.size()),
                    2, java.math.RoundingMode.HALF_UP);
            })));

For audited reports, double averaging introduces floating-point drift. Use BigDecimal with explicit rounding.

What about combining both steps with collectingAndThen?

JAVA
import static java.util.stream.Collectors.*;

Optional<Map.Entry<String, Double>> result = employees.stream()
    .collect(collectingAndThen(
        groupingBy(Employee::getDepartment,
            averagingDouble(e -> e.getSalary().doubleValue())),
        map -> map.entrySet().stream()
            .max(Map.Entry.comparingByValue())));

This wraps both steps into a single collect call, though the two-step approach is more readable.

What are common interview follow-up questions?

  • "How do you find the department with the lowest average?" Replace max with min.
  • "How do you exclude departments with fewer than 3 employees?" Filter the original stream or the result map.
  • "How do you use exact BigDecimal arithmetic?" Group, then compute average per group with BigDecimal reduce and divide.

Visual Overview

DIAGRAM
  Step 1: groupingBy(dept, averagingDouble(salary))
  ┌────────────────────────────────────┐
  │  TRADING     → Rs.1,500,000.00    │
  │  RISK        → Rs.1,200,000.00    │
  │  OPERATIONS  → Rs.900,000.00      │
  │  COMPLIANCE  → Rs.1,050,000.00    │
  └────────────────────────────────────┘

  Step 2: max(comparingByValue())
  → TRADING (Rs.1,500,000.00) ← highest

Key Takeaway

Finding the department with the highest average salary uses the same two-step pattern as finding the largest department. Step 1 groups by department with averagingDouble as the downstream. Step 2 streams the entrySet and finds max by value.

For tied departments, find the max average first, then filter all entries matching that value. For a complete ranking, sort the entrySet by value descending and collect to a LinkedHashMap.

Remember one sentence: groupingBy with averagingDouble produces per-department averages, then max on the entrySet finds the highest-paying department.

---

Share
Use ← → arrow keys to navigate