Back to Stream: map & Transform
Q7Question 7 of 34

Extract a list of all employee names from the employee list

Key Concepts
  • map() applies a Function<T,R> to each element, producing a new stream of the transformed values
  • Employee::getName is a method reference equivalent to the lambda e -> e.getName()
  • map is strictly one-to-one: every input produces exactly one output, so the output stream has the same size
  • collect(Collectors.toList()) materialises the stream into a List; Java 16+ offers the shorter toList()
  • map changes the stream's element type from Employee to String but never modifies the source list
  • Use flatMap instead of map when one input should produce zero or many outputs

Definition

`map` transforms each element into something else, one in and one out, producing a new stream of the results.
  • Stream.map(Function) applies a one-argument function to every element, producing a new stream of transformed values.
  • Method reference Employee::getName is preferred over the lambda e -> e.getName() when simply calling an existing getter.
  • One-to-one relationship: every input element produces exactly one output element.
  • Terminal collector collect(Collectors.toList()) or Java 16+ toList() materialises the stream.
  • The source collection is never modified; map produces a brand-new stream.

The HR clerk at the National Bank of India has a stack of full employee files but the manager only wants a printed list of names. She goes through each file and copies just the name onto a fresh sheet. map is that act of pulling one piece out of each item to build a new, simpler list.

Understanding the Concepts

What does map() do?

The map method on a stream takes a Function and applies it to every element, transforming type T into type R. For name extraction the function takes an Employee and returns its name String, so map changes the stream's element type from Employee to String. The relationship is strictly one-to-one: every input produces exactly one output, so the output stream has the same number of elements as the input.

How do you extract employee names with map()?

You can write the function as a lambda e -> e.getName() or, more concisely, as a method reference Employee::getName. The method reference is preferred when it simply calls an existing method, because it is shorter and signals intent clearly.

JAVA
package com.bank.hr;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

public class ExtractNames {
    public static void main(String[] args) {
        List<Employee> staff = List.of(
            new Employee("Rajesh",  "Loans",   new BigDecimal("95000")),
            new Employee("Priya",   "IT",      new BigDecimal("120000")),
            new Employee("Amit",    "Finance", new BigDecimal("85000")),
            new Employee("Kavita",  "Loans",   new BigDecimal("78000")));

        // Using method reference
        List<String> names = staff.stream()
            .map(Employee::getName)
            .collect(Collectors.toList());

        System.out.println(names);
    }
}
TEXT
[Rajesh, Priya, Amit, Kavita]

How is map() different from flatMap()?

| Feature | map() | flatMap() |
|---|---|---|
| Relationship | One-to-one | One-to-many |
| Return type of function | Single value R | Stream |
| Flattening | No | Yes, merges inner streams |
| Use case | Extract a field | Expand nested collections |

JAVA
// map: one Employee -> one String (name)
staff.stream().map(Employee::getName);

// flatMap: one Department -> many Employees
departments.stream().flatMap(d -> d.getEmployees().stream());

What are common mistakes?

Mistake: trying to use map when the function returns a collection, then wondering why the result is a list of lists.

JAVA
// WRONG: map returns Stream<List<String>>, not Stream<String>
List<List<String>> nested = departments.stream()
    .map(Department::getEmployeeNames)   // each dept returns a List<String>
    .collect(Collectors.toList());       // List<List<String>>

// CORRECT: use flatMap to flatten
List<String> flat = departments.stream()
    .flatMap(d -> d.getEmployeeNames().stream())
    .collect(Collectors.toList());       // List<String>

What about Java 16+ toList()?

Java 16 introduced Stream.toList() as a convenience terminal operation that returns an unmodifiable list.

JAVA
// Java 8-15
List<String> names = staff.stream()
    .map(Employee::getName)
    .collect(Collectors.toList());   // mutable ArrayList

// Java 16+
List<String> names = staff.stream()
    .map(Employee::getName)
    .toList();                       // unmodifiable list

The key difference is that toList() returns an unmodifiable list, so calling names.add("New") throws UnsupportedOperationException. Use collect(Collectors.toList()) when you need to mutate the result.

What about null safety?

If any employee's name could be null, the map itself does not fail, but downstream operations such as sorting or joining might throw a NullPointerException.

JAVA
// Guard: filter nulls before downstream operations
List<String> safeNames = staff.stream()
    .map(Employee::getName)
    .filter(java.util.Objects::nonNull)
    .collect(Collectors.toList());

What about chaining map with other operations?

map is an intermediate operation, so it can be chained freely with filter, sorted, and other operations in a single pipeline.

JAVA
// Extract names of Loans department employees, sorted
List<String> loanNames = staff.stream()
    .filter(e -> "Loans".equals(e.getDepartment()))
    .map(Employee::getName)
    .sorted()
    .collect(Collectors.toList());

System.out.println(loanNames);
TEXT
[Kavita, Rajesh]

What should a senior engineer know?

  • map is lazy: it does not execute until a terminal operation triggers the pipeline.
  • map preserves encounter order on ordered streams, so the output list has the same order as the input.
  • For primitive results use mapToInt, mapToLong, or mapToDouble to avoid boxing overhead.
  • The source collection is never modified; map produces a brand-new stream, making it safe for concurrent reads.

What are common interview follow-up questions?

  • "What is the difference between map and flatMap?" map is one-to-one; flatMap is one-to-many with flattening.
  • "Does map modify the source list?" No, it produces a new stream.
  • "When would you use mapToInt instead of map?" When the result is a primitive int, to avoid boxing overhead.

Visual Overview

DIAGRAM
  List<Employee>
  ┌──────────────────────────────────────────┐
  │ Rajesh (Loans, 95000)                    │
  │ Priya  (IT, 120000)                      │
  │ Amit   (Finance, 85000)                  │
  │ Kavita (Loans, 78000)                    │
  └──────────────────────────────────────────┘
        │
        │  .stream().map(Employee::getName)
        │  Function<Employee, String>
        ▼
  Stream<String>
  ┌──────────────────────────────────────────┐
  │ "Rajesh", "Priya", "Amit", "Kavita"     │
  └──────────────────────────────────────────┘
        │
        │  .collect(Collectors.toList())
        ▼
  List<String> [Rajesh, Priya, Amit, Kavita]

Key Takeaway

To extract one field out of each object I use the map operation, which applies a function to every element and produces a new stream of the transformed values. For names I map with Employee::getName, which changes the stream's element type from Employee to String, and then I collect the result into a list. Because map is strictly one-to-one, the output list has exactly the same number of elements as the input.

In my banking project at the National Bank of India this was a staff roll-call sheet for a branch meeting. The HR system stores rich employee objects with salary and department, but the meeting only needed a flat list of names, so I streamed the employees and mapped each one to just its name. I used a method reference rather than a full lambda because it simply calls an existing getter, which is shorter and signals the intent clearly.

The distinction between map and flatMap is a frequent interview discriminator. Map is one-to-one, so each input yields exactly one output and nothing is flattened. If my function had returned a collection for each element I would end up with a stream of collections, and that is exactly where flatMap is needed. On newer Java I can call toList() directly on the stream to get an unmodifiable list when I do not need to mutate the result.

Remember one sentence: map(Employee::getName) transforms each employee into its name string, one-to-one, and collect gathers them into a list.

---

Share
Use ← → arrow keys to navigate