map과 flatmap은 스트림의 요소를 변환하거나 평탄화하는 데 사용되는 중간 연산.
map은 요소를 변환하는 데 사용되며, flatMap은 리스트, 배열, Optional과 같은 중첩된 구조를 단순화할 때 주로 사용된다.
map()
-> 변환 후에도 스트림의 구조를 유지 (즉, Stream<T>를 Stream<U>로 변환)
-> 한 개의 입력 값 → 한 개의 출력 값 (1:1 매핑)
map() 사용처:
-> 단순 변환 (e.g. String → Integer)
-> 리스트에서 특정 필드 추출 (List<User> → List<String>)
flatMap()
-> 변환 후 스트림을 평탄화 (즉, Stream<Stream<U>>를 Stream<U>로 변환)
-> 한 개의 입력 값 → 여러 개의 출력 값 (1:N 매핑, 중첩 제거)
-> 스트림 내부의 스트림을 하나의 스트림으로 만들어야 할 때 사용
flatMap() 사용처:
-> 리스트의 리스트 평탄화 (List<List<T>> → List<T>)
-> 문자열을 단어로 변환 (String → List<String>)
-> Optional<Optional<T>> 평탄화
map은 스트림의 각 요소에 함수를 적용하여 새로운 요소로 변환시킴. 각 입력 요소에 대해 하나의 출력 요소를 생성하므로, 스트림의 길이는 변하지 않음.
일반적으로 객체의 특정 필드 추출, 데이터 변환, 데이터 가공 등의 목적으로 사용된다.
List<String> words = Arrays.asList("apple", "banana", "cherry");
List<Integer> wordLengths = words.stream()
.map(String::length) // 각 단어의 길이로 변환
.collect(Collectors.toList());
System.out.println(wordLengths); // 출력: [5, 6, 6]
실행 과정
1) "apple" → 5
2) "banana" → 6
3) "cherry" → 6
4) 결과: [5, 6, 6]
map()의 특징
변환된 요소는 하나씩 그대로 유지됨.
Stream<T> → Stream<U> 변환.
class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
}
List<User> users = Arrays.asList(new User("Alice", 25), new User("Bob", 30));
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());
System.out.println(names); // 출력: [Alice, Bob]
map(User::getName)을 통하여 User 객체에서 name 값만 추출List<String> numbers = Arrays.asList("1", "2", "3");
List<Integer> intNumbers = numbers.stream()
.map(Integer::parseInt)
.collect(Collectors.toList());
System.out.println(intNumbers); // 출력: [1, 2, 3]
map(Integer::parseInt) 메서드를 이용하여 String 값을 Integer로 변경List<String> words = Arrays.asList("hello", "world");
List<String> upperWords = words.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upperWords); // 출력: [HELLO, WORLD]
map(String::toUpperCase)을 통하여 문자열을 대문자로 변환시킴flatMap 메서드도 map 메서드처럼 각 요소에 함수를 적용하여 새로운 요소로 변환시킨다. 다만, 다른 점은 생성된 여러 스트림을 하나의 스트림으로 평탄화(flatten)한다. 즉, 중첩된 스트림 구조를 단일 스트림으로 변환한다.
List<List<String>> nestedList = Arrays.asList(
Arrays.asList("Alice", "Bob"),
Arrays.asList("Charlie", "David"),
Arrays.asList("Eve", "Frank")
);
List<String> flatList = nestedList.stream()
.flatMap(List::stream) // 리스트 내부의 리스트를 풀어서 하나의 스트림으로 만듦
.collect(Collectors.toList());
System.out.println(flatList); // 출력: [Alice, Bob, Charlie, David, Eve, Frank]
"Alice", "Bob" → Stream.of("Alice", "Bob")"Charlie", "David" → Stream.of("Charlie", "David")"Eve", "Frank" → Stream.of("Eve", "Frank")Stream<String>을 합쳐서 하나의 Stream<String>으로 만듦.["Alice", "Bob", "Charlie", "David", "Eve", "Frank"]Stream<List<T>> → Stream<T> 변환 (즉, 중첩된 구조를 평탄화).List<List<String>> nestedList = Arrays.asList(
Arrays.asList("Alice", "Bob"),
Arrays.asList("Charlie", "David"),
Arrays.asList("Eve", "Frank")
);
List<String> flatList = nestedList.stream()
.flatMap(List::stream) // 리스트 내부의 리스트를 풀어서 하나의 스트림으로 만듦
.collect(Collectors.toList());
System.out.println(flatList); // 출력: [Alice, Bob, Charlie, David, Eve, Frank]
flatMap(List::stream) 메서드를 이용하여 단일 리스트로 평탄화 시킨 예시List<String> sentences = Arrays.asList("Hello World", "Java Stream API");
List<String> words = sentences.stream()
.flatMap(sentence -> Arrays.stream(sentence.split(" ")))
.collect(Collectors.toList());
System.out.println(words); // 출력: [Hello, World, Java, Stream, API]
split(" ")을 이용해 문장을 단어 단위로 분할한 후, flatMap으로 평탄화Optional<Optional<String>> optional = Optional.of(Optional.of("Hello"));
Optional<String> flatOptional = optional.flatMap(o -> o);
System.out.println(flatOptional.get()); // 출력: Hello
Optional<Optional<T>>을 flatMap을 사용하여 Optional<T>로 변환. 내부를 펼쳐서(flat) 반환하기 때문에 이렇게 사용 가능map을 사용했다면 .get()을 두 번 호출해야 "Hello"에 접근 가능class Order {
private String productName;
public Order(String productName) {
this.productName = productName;
}
public String getProductName() {
return productName;
}
}
class User {
private String name;
private List<Order> orders;
public User(String name, List<Order> orders) {
this.name = name;
this.orders = orders;
}
public List<Order> getOrders() {
return orders;
}
}
List<User> users = Arrays.asList(
new User("Alice", Arrays.asList(new Order("Laptop"), new Order("Mouse"))),
new User("Bob", Arrays.asList(new Order("Keyboard"), new Order("Monitor")))
);
List<String> allOrders = users.stream()
.flatMap(user -> user.getOrders().stream())
.map(Order::getProductName)
.collect(Collectors.toList());
System.out.println(allOrders); // 출력: [Laptop, Mouse, Keyboard, Monitor]
flatMap 사용