Definition
map.values().stream()gives aStreamof all value lists.- >
flatMap(List::stream)opens each inner list and concatenates them into one flat stream.- Three views:
keySet()for keys,values()for values,entrySet()for key-value pairs. - Order: HashMap gives undefined order; LinkedHashMap preserves insertion order; TreeMap sorts by key.
- Null guard: protect against null inner lists if the map allows null values.
The HR system at the National Bank of India keeps a filing cabinet where each drawer is labelled with a department and holds that department's employee files. To get one combined list of all employees, the clerk ignores the labels and empties every drawer into one pile.
Understanding the Concepts
How do you flatten a map's values?
A map has three things you can stream: keys, values, and entries. Here we only need the employees, which live in the values, so we stream map.values() and flatMap each inner list.
package com.bank.hr;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
public class FlattenMapValues {
public static void main(String[] args) {
Map<String, List<Employee>> byDept = Map.of(
"Loans", List.of(
new Employee("Rajesh", "Loans", new BigDecimal("95000")),
new Employee("Kavita", "Loans", new BigDecimal("78000"))),
"IT", List.of(
new Employee("Priya", "IT", new BigDecimal("120000"))),
"Finance", List.of(
new Employee("Amit", "Finance", new BigDecimal("85000"))));
List<Employee> all = byDept.values().stream()
.flatMap(List::stream)
.collect(Collectors.toList());
all.forEach(e -> System.out.println(e.getName()));
}
}
Rajesh
Kavita
Priya
Amit
When do you stream entrySet instead of values?
If you need the department label alongside each employee, stream entrySet() and carry the key through.
| Need | Stream view | Example |
|---|---|---|
| Just employees | values().stream() | flatMap(List::stream) |
| Employee + department label | entrySet().stream() | flatMap with entry key |
| Just department names | keySet().stream() | Direct stream of keys |
// Carry the department key with each employee
byDept.entrySet().stream()
.flatMap(entry -> entry.getValue().stream()
.map(e -> entry.getKey() + ": " + e.getName()))
.forEach(System.out::println);
Loans: Rajesh
Loans: Kavita
IT: Priya
Finance: Amit
What about map iteration order?
| Map type | Iteration order |
|---|---|
| HashMap | Undefined (may change between runs) |
| LinkedHashMap | Insertion order |
| TreeMap | Sorted by key (natural or comparator) |
When the order of the flattened list matters, use a LinkedHashMap or TreeMap instead of a plain HashMap.
What are common mistakes?
Mistake: calling .stream() on a null inner list when a map entry has a null value.
// WRONG: null value in map causes NPE
Map<String, List<Employee>> map = new HashMap<>();
map.put("Loans", null); // null value!
map.values().stream()
.flatMap(List::stream) // NPE on null!
.collect(Collectors.toList());
// CORRECT: filter out null values
map.values().stream()
.filter(Objects::nonNull)
.flatMap(List::stream)
.collect(Collectors.toList());
What about counting all employees across departments?
long totalCount = byDept.values().stream()
.flatMap(List::stream)
.count();
System.out.println("Total employees: " + totalCount);
What should a senior engineer know?
- Choose the map view that matches the data you need: values for just the data, entrySet for data plus keys.
- The result order is tied to the map's iteration order, which is a common source of test flakiness with HashMap.
List::streamis a method reference equivalent tolist -> list.stream().- For very large maps, the flatten is lazy and processes one list at a time.
What are common interview follow-up questions?
- "How do you also include the department name?" Stream entrySet and carry the key.
- "How do you get a deterministic order?" Use LinkedHashMap or TreeMap.
- "What if the map has null values?" Filter them out before flatMapping.
Visual Overview
Map<String, List<Employee>>
┌──────────────────────────────────────┐
│ Loans → [Rajesh, Kavita] │
│ IT → [Priya] │
│ Finance → [Amit] │
└──────────────────────────────────────┘
│
│ values().stream()
▼
Stream<List<Employee>>
[[Rajesh,Kavita], [Priya], [Amit]]
│
│ flatMap(List::stream)
▼
Stream<Employee>
[Rajesh, Kavita, Priya, Amit]
│
│ collect(toList())
▼
List<Employee> [Rajesh, Kavita, Priya, Amit]
Key Takeaway
To flatten a map whose values are lists, I stream the map's values and flatMap each inner list into the overall stream. Because I only needed the employees I streamed the values, which gave a stream of lists, and then flatMap with List::stream concatenated them into one flat stream.
In my banking project at the National Bank of India the HR data stored employees grouped by department in a map, but a bank-wide payroll run needs one flat list of everyone. Streaming the values and flatMapping gave exactly that.
The senior points I raise are choosing the right map view (values for data, entrySet for data plus keys), being aware that HashMap order is undefined while TreeMap is sorted, and guarding against null inner lists.
Remember one sentence: map.values().stream().flatMap(List::stream) flattens a grouped map's value lists into one flat employee stream.
---