Definition
- **groupingBy(e -> e.getJoinDate().getYear(), counting())** produces `Map<Integer, Long>` of joins per year. - **max(comparingByValue())** on the entrySet finds the peak hiring year. - Same **group-count-max** pattern as department and city questions.
The bank's annual report asks: 'In which year did we hire the most people?' Count joiners per year, then find the peak year.
Understanding the Concepts
How do you find the peak hiring year?
package com.bank.hr;
import java.util.*;
import java.util.stream.Collectors;
public class PeakHiringYear {
public static void main(String[] args) {
List<Employee> employees = Employee.getSampleEmployees();
Map<Integer, Long> joinsByYear = employees.stream()
.collect(Collectors.groupingBy(
e -> e.getJoinDate().getYear(),
Collectors.counting()));
Optional<Map.Entry<Integer, Long>> peak = joinsByYear.entrySet()
.stream()
.max(Map.Entry.comparingByValue());
peak.ifPresent(e ->
System.out.println("Peak year: " + e.getKey()
+ " (" + e.getValue() + " hires)"));
// Chronological trend
new TreeMap<>(joinsByYear).forEach((year, count) ->
System.out.println(" " + year + ": " + count));
}
}
Peak year: 2021 (3 hires)
2005: 1
2015: 1
2018: 1
2019: 1
2021: 3
2022: 1
2023: 1
2024: 1
What are common mistakes?
Mistake: using getYear() on a null joinDate.
// Guard against null join dates
Map<Integer, Long> safe = employees.stream()
.filter(e -> e.getJoinDate() != null)
.collect(Collectors.groupingBy(
e -> e.getJoinDate().getYear(),
Collectors.counting()));
What about showing a chronological hiring trend?
new TreeMap<>(joinsByYear).forEach((year, count) -> {
String bar = "#".repeat(count.intValue());
System.out.printf("%d: %s (%d)%n", year, bar, count);
});
What about finding the quarter with the most hires?
import java.time.temporal.IsoFields;
Map<Integer, Long> joinsByQuarter = employees.stream()
.filter(e -> e.getJoinDate() != null)
.collect(Collectors.groupingBy(
e -> e.getJoinDate().get(IsoFields.QUARTER_OF_YEAR),
Collectors.counting()));
What about detecting hiring gaps?
TreeMap<Integer, Long> sorted = new TreeMap<>(joinsByYear);
int firstYear = sorted.firstKey();
int lastYear = sorted.lastKey();
for (int year = firstYear; year <= lastYear; year++) {
if (!sorted.containsKey(year)) {
System.out.println("No hires in: " + year);
}
}
What about grouping by month instead of year?
import java.time.Month;
Map<Month, Long> joinsByMonth = employees.stream()
.filter(e -> e.getJoinDate() != null)
.collect(Collectors.groupingBy(
e -> e.getJoinDate().getMonth(),
Collectors.counting()));
What are the edge cases?
If no employees have a join date, the map is empty and max returns Optional.empty(). Guard against null joinDate before calling getYear().
What should a senior engineer know?
At National Bank of India, Rajesh builds a workforce planning report that identifies peak hiring years for budget forecasting. The HR team for account operations (account SAV2001 processing team) uses this data to plan onboarding capacity.
// Production pattern: peak year with headcount and average salary
Map<Integer, DoubleSummaryStatistics> yearStats = employees.stream()
.filter(e -> e.getJoinDate() != null)
.collect(Collectors.groupingBy(
e -> e.getJoinDate().getYear(),
Collectors.summarizingDouble(
e -> e.getSalary().doubleValue())));
yearStats.forEach((year, stats) ->
System.out.printf("%d: %d hires, avg salary: %.0f%n",
year, stats.getCount(), stats.getAverage()));
For large datasets, groupingByConcurrent with a parallel stream avoids the merge overhead. Use TreeMap as the map factory (groupingBy(classifier, TreeMap::new, counting())) when you need sorted output without a separate sort step.
What are common interview follow-up questions?
- "How do you show a hiring trend over time?" Collect to TreeMap for chronological order.
- "How do you find the quarter with the most hires?" Use getJoinDate().get(IsoFields.QUARTER_OF_YEAR).
Visual Overview
groupingBy(joinYear, counting()) ┌────────────────────────┐ │ 2005 → 1 │ │ 2015 → 1 │ │ 2021 → 3 ← peak │ │ 2022 → 1 │ │ 2024 → 1 │ └────────────────────────┘ max(comparingByValue()) → 2021
Key Takeaway
Finding the peak hiring year uses groupingBy with the year extracted from the join date as the classifier and counting as the downstream, then max by value. Collect to a TreeMap for chronological display.
Remember one sentence: groupingBy(joinYear, counting()) then max by value finds the year with the most hires.
---