Java

[Java] Stream API의 map과 flatMap의 차이점

leejunkim 2025. 6. 2. 10:54

map()

map()은 각 요소를 변환하여 새로운 요소로 매핑하는 함수이다 (1:1매핑이라고 생각하면 된다).

데이터 변환을 하고 싶을 때 사용한다.

가장 많이 쓰이는 용도는 Stream이다 - 누군가가 자바의 map()을 언급한다면 Stream API의 map()을 얘기하는 경우가 대부분일 것이다.

 

간단한 map()과 String의 toUpperCase()를 사용한 코드 예제이다:

List<String> namesLower = Arrays.asList("mary", "john", "walt");

// Stream API의 map()을 사용해서 대문자로 변환
List<String> namesUpper = namesLower.stream()
	.map(String::toUpperCase)
    .collect(Collectors.toList());
    
System.out.println(namesUpper); // [MARY, JOHN, WALT]

 

아예 다른 자료형으로 변환시켜줄 수도 있다:

List<String> namesLower = Arrays.asList("mary", "john", "walt");

// Stream API의 map()을 사용해서 단어의 길이로 변환
List<Integer> namesUpper = namesLower.stream()
	.map(String::length)
	.collect(Collectors.toList());

System.out.println(namesUpper); // [4, 4, 4]

flatMap()

flatMap()은 스트림의 각 요소를 스트림으로 변환한 후 모든 스트림을 1차원으로 평면화 시켜준다.

중첩 데이터 처리를 하고 싶을 때 사용한다.

List<List<Integer>> nestedList = Arrays.asList(
    Arrays.asList(1, 1),
    Arrays.asList(2, 2)
);

List<Integer> list = nestedList.stream()
    .flatMap(Collection::stream)
    .toList();
    
System.out.println(list); // [1, 1, 2, 2]

 

flapMap()과 map()을 같이 사용할 수 있다:

List<List<Integer>> nestedList = Arrays.asList(
        Arrays.asList(1, 1),
        Arrays.asList(2, 2)
);

List<Integer> list = nestedList.stream()
        .flatMap(Collection::stream)
        .map(n -> n + 1)
        .toList();

System.out.println(list); // [2, 2, 3, 3]

 

정리

주요 차이점을 정리하자면 이렇게 된다:

특징 map() flatMap()
관계 1:1 1:N
출력
입력 스트림과 동일한 개수의 요소를 가진 스트림 입력 스트림의 요소 개수와 같거나 더 많은 (또는 적은) 요소를 가진 스트림 (flatten/평탄화됨)
중첩 구조 유지? 유지됨 (List<List<T>> 등) 제거됨 (List<T>) 형태
성능 상대적으로 메모리 사용 적음 중간 스트림 생성 -> 메모리 사용 증가 가

 

단순 값을 변환하거나 객체의 필드를 추줄하고 싶을 때는 map(), 1:N 구조로 변환하거나 중첩된 데이터를 풀고 싶을 때는 flatMap()을 사용한다.