map vs flatMap

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • map() transforms one object into another object. (One-to-One).
  • flatMap() transforms one object into a Stream of objects, and then “flattens” all those streams into a single massive stream. (One-to-Many).

Concept

The map operation

Use map when every element in your stream corresponds to exactly one output element.
If you have a Stream<String> and you map each string to its length, you get a Stream<Integer>.

The flatMap operation

Use flatMap when you have a stream of complex objects (like Lists), and you want to extract all the items inside those lists into a single, flat stream.
If you have a Stream<List<String>> (a stream of lists), and you use map, you just get a transformed Stream<List<String>>. But if you use flatMap, it extracts the Strings from every inner list and merges them, resulting in a single Stream<String>.

Examples

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class MapVsFlatMap {
    public static void main(String[] args) {
        
        // --- 1. map() Example ---
        List<String> words = Arrays.asList("hello", "world");
        
        List<Integer> lengths = words.stream()
            .map(String::length) // 1 word -> 1 length
            .collect(Collectors.toList());
            
        System.out.println(lengths); // [5, 5]
        
        // --- 2. flatMap() Example ---
        List<List<String>> listOfLists = Arrays.asList(
            Arrays.asList("a", "b"),
            Arrays.asList("c", "d"),
            Arrays.asList("e", "f")
        );
        
        // If we used map(List::stream), we would get Stream<Stream<String>>
        // flatMap merges them all into a single Stream<String>
        List<String> flatList = listOfLists.stream()
            .flatMap(List::stream) 
            .collect(Collectors.toList());
            
        System.out.println(flatList); // [a, b, c, d, e, f]
    }
}

Interview Questions

Q: When should you use flatMap with Optional?
A: In Java 8, Optional acts somewhat like a stream of 0 or 1 elements. If you have an Optional<User> and you call map(User::getAddress), you get an Optional<Address>. But what if getAddress() itself returns an Optional<Address>? Using map would result in a nested Optional<Optional<Address>>. In this scenario, you use flatMap(User::getAddress) to flatten it into a single Optional<Address>.

Q: Does flatMap improve performance?
A: Not inherently. flatMap is a structural operation used to change the shape of your data (from nested collections to a flat sequence). It does extra work to manage and merge multiple streams. You use it because the logic dictates it, not to optimize performance.