Language & Framework/Java

Java Stream API - map() vs flatMap() 정복하기

밍구링구리 2025. 6. 15. 16:18
728x90

Java의 Stream API는 데이터를 함수형 스타일로 처리할 수 있는 강력한 도구다.

그중에서도 `map()`과 `flatMap()`은 가장 자주 사용되는 중간 연산자이다.

하지만 두 메서드는 이름이 비슷해 헷갈리기 쉽다.

이번 글에서는 두 메서드의 차이와 활용법을 예제 중심으로 쉽게 정리해보겠다.


🔄 map() - 요소를 변환

`map()`은 스트림의 각 요소를 일대일로 변환할 때 사용한다.

주로 원하는 필드만 추출하거나 특정 형태로 변환할 떄 사용한다.

예시)

  • 각 요소를 새로운 값으로 매핑
  • 변환 결과를 새 스트림으로 반환
  • 내부적으로 `Function<T, R>`이 사용됨

📌 예제 1: 문자열을 대문자로

List<String> names = Arrays.asList("kimcoding", "javalee", "hackerna", "luckyguy");

names.stream()
     .map(String::toUpperCase)
     .forEach(System.out::println);

출력:

KIMCODING
JAVALEE
HACKERNA
LUCKYGUY

 

📌 예제 2: 숫자 변환

List<Integer> numbers = Arrays.asList(1, 3, 6, 9);

numbers.stream()
       .map(n -> n * 3)
       .forEach(System.out::println);

출력:

3
9
18
27

📂 flatMap() - 중첩을 펼치다

`flatMap()`은 중첩된 스트림의 구조를 스트림의 각 요소를 스트림으로 변환하여

모든 내부 스트림을 하나로 평탄화(flatten) 한다.

  • 중첩된 구조 해제 (2차원 → 1차원)
  • `Stream<Stream<T>> → Stream<T>`
  • 내부적으로 `Function<T, Stream<R>>` 사용

📌 예제: 중첩 리스트 평탄화

List<List<String>> nestedList = Arrays.asList(
    Arrays.asList("JAVA", "SPRING"),
    Arrays.asList("java", "spring")
);

nestedList.stream()
          .flatMap(Collection::stream)
          .forEach(System.out::println);

출력:

JAVA
SPRING
java
spring

🧠 map() vs flatMap()의 차이점

같은 데이터로 두 방식 비교해보자!

List<String> sentences = Arrays.asList("a b", "c d");

// map 사용
List<Stream<String>> withMap = sentences.stream()
    .map(s -> Arrays.stream(s.split(" ")))   // Stream<Stream<String>>
    .collect(Collectors.toList());

// flatMap 사용
List<String> withFlatMap = sentences.stream()
    .flatMap(s -> Arrays.stream(s.split(" ")))   // Stream<String>
    .collect(Collectors.toList());
  • `map()`을 사용하면 각 문장이 단어 배열로 나뉜다 → Stream<Stream<String>>
    • `"a b"` → `Stream.of("a", "b")`
    • `"c d"` → `Stream.of("c", "d")`
// 출력결과
a
b
c
d
  • `flatMap()`을 사용하면 모든 단어가 하나의 스트림으로 평탄화됨 → Stream<String>
// 출력결과
["a", "b", "c", "d"]

🔍 map() vs flatMap() 비교

항목 `map()` `flatMap()`
목적 요소 변환 중첩된 요소를 펼침
결과 구조 Stream<T> 또는 Stream<Stream<T>> Stream<T>
변환 수 1:1 변환 1:N 변환 + 평탄화
사용 예 문자열 대문자 변환, 수학 연산 리스트 안의 리스트 펼치기, 문장 → 단어

💡 언제 무엇을 써야 할까?

각 요소를 하나의 값으로 변환할 때는?

  • `map()` 메소드 사용!
    • 간단하게 변환할 수 있음(ex. 포맷 변경, 계산 등)

각 요소를 여러 값으로 변환 후 펼칠 때는?

  • `flatMap()` 메소드 사용!
    • 중첩된 구조를 해제할 수 있음(ex. 배열, 리스트)

✏️ 마무리

Java Stream API의 `map()`과 `flatMap()`은 개념이 비슷해 보이지만,

중첩 구조의 유무와 평탄화 여부에 따라 확연히 다르다!

“map()은 변환, flatMap()은 펼친다”

728x90