/////
Search
Duplicate
3️⃣

매핑

특정 객체에서 특정 데이터를 선택하는 작업은 데이터 처리 과정에서 자주 수행되는 연산이다.
예를 들어 SQL의 테이블에서 특정 열만 선택할 수 있다.
스트림 API의 mapflatMap 메서드는 특정 데이터(필드)를 선택하는 기능을 제공한다.

1. 스트림의 각 요소에 함수 적용하기

스트림은 함수를 인수로 받는 map 메서드를 지원한다.
인수로 제공된 함수는 각 요소에 적용되며 함수를 적용한 결과가 새로운 요소로 매핑된다.
다음은 Dish::getNamemap 메서드로 전달해서 스트림의 요리명을 추출하는 코드다.
List<String> dishNames = menu.stream() .map(Dish::getName) .collect(toList());
Java
복사
getName은 문자열을 반환하므로 출력 스트림은 Stream<String> 형식을 갖는다.
다른 예제를 살펴보면 map 메서드가 어떤 일을 수행하는지 더 잘 이해할 수 있다.
단어 리스트가 주어졌을 때 각 단어가 포함하는 글자 수의 리스트를 반환한다고 가정하자. 어떻게 이 작업을 구현할 수 있을까?
각 요소에 적용할 함수는 단어를 인수로 받아서 길이를 반환해야 하므로 String::lengthmap에 전달해서 문제를 해결할 수 있다.
List<String> words = Arrays.asList("Modern", "Java", "In", "Action"); List<Integer> wordLengths = words.stream() .map(String::length) .collect(toList());
Java
복사
다시 요리의 이름을 가져오는 예제로 돌아가서 요리 이름의 길이를 구하고 싶다면 다음과 같이 map 메소드를 연쇄해서 사용하면 된다.
List<String> dishNames = menu.stream() .map(Dish::getName) .map(String::length) .collect(toList());
Java
복사

2. 스트림 평면화

메서드 map을 이용해서 리스트의 각 단어의 길이를 반환하는 방법을 확인했다.
이를 응용해서 리스트에서 고유 문자로 이루어진 리스트를 반환해보자.
[”Hello”, “World”] 리스트가 있다면 결과로 [”H”, “e”, “l”, “o”, “W”, “r”, “d”]를 포함하는 리스트가 반환되어야 한다.
리스트에 있는 각 단어를 문자로 매핑한 다음에 distinct로 중복된 문자를 필터링해서 쉽게 문제를 해결할 수 있을 것이라고 추측할 수도 있을 것이다.
words.stream() .map(word -> word.split("")) .distinct() .collect(toList());
Java
복사
위 코드에서 map으로 전달한 람다는 각 단어의 String[]을 반환한다는 점이 문제다. 따라서 map 메소드가 반환한 스트림의 형식은 Stream<String[]>이다.
하지만 우리가 원한 형식은 Stream<String>이다.. 어떻게 이 문제를 해결할 수 있을까?
다행히 flatMap이라는 메서드를 이용해서 이 문제를 해결할 수 있다.
mapArrays.stream 활용
우선 배열 스트림 대신 문자열 스트림이 필요하다. 다음 코드에서 보여주는 것처럼 문자열을 받아 스트림을 만드는 Arrays.stream() 메서드가 있다.
String[] arrayOfWords = {"Goodbye", "World"}; Stream<String> streamOfWords = Arrays.stream(arrayOfWords);
Java
복사
위 예제에서 파이프라인에 Arrays.stream() 메서드를 적용해보자.
word.stream() .map(word -> word.split("")) .map(Arrays::stream) .distinct() .collect(toList());
Java
복사
결국 스트림 리스트(엄밀히는 List<Stream<String>>)가 만들어지면서 문제가 해결되지 않았다.
문제를 해결하려면 먼저 각 단어를 개별 문자열로 이루어진 배열로 만든 다음에 각 배열을 별도의 스트림으로 만들어야 한다.
flatMap 사용
flatMap을 사용하면 다음처럼 문제를 해결할 수 있다.
List<String> uniqueCharacters = words.stream() .map(word -> word.split("")) .flatMap(Arrays::stream) .distinct() .toList());
Java
복사
flatMap은 각 배열을 스트림이 아니라 스트림의 콘텐츠로 매핑한다.
map(Arrays::stream)과 달리 flatMap은 하나의 평면화된 스트림을 반환한다.
요약하면 flatMap 메서드는 스트림의 각 값을 다른 스트림으로 만든 다음에 모든 스트림을 하나의 스트림으로 연결하는 기능을 수행한다.