Definition
- getJoinDate().getYear() extracts the year from each employee's join date as an int.
- groupingBy collects employees sharing the same year into a list.
- The result is
Mapkeyed by year.> - TreeMap::new gives chronological year order for reports.
- Guard null join dates before calling getYear().
Priya at the National Bank of India files employees by the year they joined: a 2020 tray, a 2021 tray, and so on, based on the year part of their joining date.
Understanding the Concepts
How do you group by joining year?
Extract the year from the join date and use it as the classifier.
package com.bank.hr;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
public class GroupByJoinYear {
public static void main(String[] args) {
List<Employee> employees = List.of(
new Employee("Rajesh", LocalDate.of(2020, 3, 1)),
new Employee("Priya", LocalDate.of(2021, 6, 15)),
new Employee("Amit", LocalDate.of(2020, 9, 10)),
new Employee("Kavita", LocalDate.of(2022, 1, 5)),
new Employee("Neha", LocalDate.of(2021, 11, 20))
);
Map<Integer, List<Employee>> byYear = employees.stream()
.collect(Collectors.groupingBy(
e -> e.getJoinDate().getYear(),
TreeMap::new,
Collectors.toList()));
byYear.forEach((year, emps) ->
System.out.println(year + ": " + emps.stream()
.map(Employee::getName)
.collect(Collectors.joining(", "))));
}
}
2020: Rajesh, Amit
2021: Priya, Neha
2022: Kavita
How do you count hires per year?
Map<Integer, Long> hiresPerYear = employees.stream()
.collect(Collectors.groupingBy(
e -> e.getJoinDate().getYear(),
TreeMap::new,
Collectors.counting()));
hiresPerYear.forEach((year, count) ->
System.out.println(year + ": " + count + " hires"));
2020: 2 hires
2021: 2 hires
2022: 1 hires
How do you guard against null join dates?
// WRONG: NullPointerException if joinDate is null
employees.stream()
.collect(Collectors.groupingBy(
e -> e.getJoinDate().getYear()));
// CORRECT: filter nulls first
employees.stream()
.filter(e -> e.getJoinDate() != null)
.collect(Collectors.groupingBy(
e -> e.getJoinDate().getYear(),
TreeMap::new,
Collectors.toList()));
How do you group by decade instead of year?
Map<Integer, List<Employee>> byDecade = employees.stream()
.collect(Collectors.groupingBy(
e -> (e.getJoinDate().getYear() / 10) * 10));
// Keys: 2020 (for 2020-2029)
What should a senior engineer know?
- Deriving the grouping key on the fly from a date field keeps the data model clean; no redundant year column needed.
- Use TreeMap to get chronological order for cohort analysis reports.
- groupingBy only creates keys for years that have employees. To include years with zero hires, merge with a pre-built map of all expected years.
- This pattern generalises to grouping by month, quarter, or any temporal unit.
What are common interview follow-up questions?
- "How do you group by month instead of year?" Use e -> e.getJoinDate().getMonth() as the classifier. - "How do you group by year-month?" Use e -> YearMonth.from(e.getJoinDate()). - "How do you find the year with the most hires?" Stream the hires-per-year map and take max by value.
Visual Overview
Stream<Employee>
[Rajesh:2020-03, Priya:2021-06, Amit:2020-09, Kavita:2022-01, Neha:2021-11]
│
│ classifier: getJoinDate().getYear()
▼
Mapping:
Rajesh → 2020
Priya → 2021
Amit → 2020
Kavita → 2022
Neha → 2021
│
│ groupingBy (TreeMap for order)
▼
Map<Integer, List<Employee>>
┌────────────────────────────┐
│ 2020 → [Rajesh, Amit] │
│ 2021 → [Priya, Neha] │
│ 2022 → [Kavita] │
└────────────────────────────┘
Key Takeaway
To group employees by joining year, pass a classifier that extracts the year from each join date. LocalDate.getYear() returns the year as an int, and groupingBy collects employees sharing a year into a list, producing a cohort view for HR analysis.
Supply a TreeMap for chronological order and combine with counting() for hires-per-year. At the National Bank of India, this drove the annual hiring report and cohort retention analysis.
Guard against null join dates before calling getYear, and derive the key on the fly to keep the data model clean. This pattern generalises to grouping by month, quarter, decade, or any temporal unit.
Remember one sentence: groupingBy(e -> getJoinDate().getYear()) groups employees into year cohorts, and TreeMap::new ensures chronological order.
---