Diferença entre map e flatMap em Java: Entenda as Nuances

Se você trabalha com Java 8 ou versões superiores, certamente já se deparou com os métodos map e flatMap ao trabalhar com Streams. Embora ambos sejam usados para transformar elementos em uma coleção ou stream, há uma diferença crucial no seu comportamento. Neste post, vamos explicar a diferença entre map e flatMap em Java, além de mostrar quando e como utilizá-los.

O que é o método map em Java?

O método map faz parte da API de Streams do Java e é utilizado para transformar os elementos de um stream, aplicando uma função que retorna um valor para cada elemento da sequência. O resultado de map é um novo stream com os elementos transformados de acordo com a função fornecida.

Exemplo de uso do map

import java.util.*;
import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        List<String> palavras = Arrays.asList("java", "stream", "map");

        List<String> maiusculas = palavras.stream()
                                          .map(String::toUpperCase)
                                          .collect(Collectors.toList());

        System.out.println(maiusculas); // Saída: [JAVA, STREAM, MAP]
    }
}

No exemplo acima, o map converte cada string da lista para maiúsculas, gerando uma nova lista.

O que é o método flatMap em Java?

O método flatMap também faz parte da API de Streams e é semelhante ao map, mas com um comportamento importante: em vez de transformar os elementos em valores simples, ele “achata” (flat) os resultados de transformações que retornam múltiplos valores. Ou seja, flatMap é utilizado quando a função aplicada retorna um stream, e ele “aplana” esses múltiplos streams em um único stream.

Exemplo de uso do flatMap

import java.util.*;
import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        List<List<String>> listasDePalavras = Arrays.asList(
            Arrays.asList("java", "stream"),
            Arrays.asList("map", "flatMap")
        );

        List<String> todasPalavras = listasDePalavras.stream()
                                                   .flatMap(List::stream)
                                                   .collect(Collectors.toList());

        System.out.println(todasPalavras); // Saída: [java, stream, map, flatMap]
    }
}

No exemplo acima, temos uma lista de listas. Usamos flatMap para “achatar” as listas internas em um único stream, retornando uma lista de palavras sem a estrutura de listas dentro dela.

Diferença entre map e flatMap

A principal diferença entre map e flatMap está no tipo de valor retornado:

  • map: Transforma cada elemento em um novo valor, retornando um stream de elementos transformados. Cada elemento do stream original gera um único valor no stream resultante.
  • flatMap: Transforma cada elemento em um stream de valores, e depois achata esses streams em um único stream. Ou seja, ele pode gerar múltiplos elementos por cada elemento do stream original.

Exemplo ilustrativo da diferença

Imagine que você tenha um stream de palavras e deseja converter cada palavra em um stream de letras:

import java.util.*;
import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        List<String> palavras = Arrays.asList("java", "stream");

        // Usando map (retorna um stream de streams)
        List<Stream<Character>> mapResult = palavras.stream()
                                                    .map(word -> word.chars().mapToObj(c -> (char) c))
                                                    .collect(Collectors.toList());

        // Usando flatMap (achata o stream de streams em um único stream)
        List<Character> flatMapResult = palavras.stream()
                                                .flatMap(word -> word.chars().mapToObj(c -> (char) c))
                                                .collect(Collectors.toList());

        System.out.println("Resultado com map: " + mapResult);
        System.out.println("Resultado com flatMap: " + flatMapResult);
    }
}

Saída:

Resultado com map: [java.util.stream.ReferencePipeline$Head@15db9742, java.util.stream.ReferencePipeline$Head@6d06d69c]
Resultado com flatMap: [j, a, v, a, s, t, r, e, a, m]
  • Com map, cada palavra é transformada em um stream de caracteres, resultando em uma lista de streams.
  • Com flatMap, o stream de caracteres é “achatado”, resultando em um único stream de caracteres.

Quando usar map e flatMap?

Use map quando:

  • Você deseja transformar cada elemento em um valor único.
  • A função aplicada não retorna streams.

Use flatMap quando:

  • Você deseja “achatar” um stream de elementos em um único stream.
  • A função aplicada retorna múltiplos valores (um stream) por cada elemento original.

Para mais detalhes sobre manipulação de streams em Java, confira o nosso post sobre Stream API em Java: Como Funciona.

Link externo relevante

A documentação oficial sobre map e flatMap pode ser acessada aqui.


Comentários

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *