Java

Java Stream API - map() & flatMap()

9taetae9 2025. 1. 20. 09:04
728x90

Java 8μ—μ„œ λ„μž…λœ Stream APIλŠ” μ»¬λ ‰μ…˜μ„ μ²˜λ¦¬ν•˜λŠ” 효과적인 방법을 μ œκ³΅ν•œλ‹€. κ·Έ μ€‘μ—μ„œλ„ map()κ³Ό flatMap() λ©”μ„œλ“œλŠ” 데이터 λ³€ν™˜κ³Ό μ²˜λ¦¬μ— μžˆμ–΄ 핡심적인 역할을 ν•œλ‹€.

 

1. map()

<R> Stream<R> map(
        Function<? super T, // T : μž…λ ₯ νƒ€μž… (원본 슀트림의 μš”μ†Œ νƒ€μž…)
        ? extends R> mapper // R : 좜λ ₯ νƒ€μž… (μƒˆλ‘œμš΄ 슀트림의 μš”μ†Œ νƒ€μž…)
)

map() λ©”μ„œλ“œλŠ” 슀트림의 각 μš”μ†Œλ₯Ό λ‹€λ₯Έ μš”μ†Œλ‘œ λ³€ν™˜ν•˜λŠ” 1:1 맀핑을 μˆ˜ν–‰ν•œλ‹€. μž…λ ₯ μš”μ†Œ ν•˜λ‚˜λ‹Ή μ •ν™•νžˆ ν•˜λ‚˜μ˜ 좜λ ₯ μš”μ†Œκ°€ μƒμ„±λœλ‹€.

μ£Όμš” νŠΉμ§•

  • 각 μš”μ†Œλ₯Ό λ…λ¦½μ μœΌλ‘œ λ³€ν™˜
  • 슀트림의 μš”μ†Œ 개수 μœ μ§€ (one-to-one)
  • 원본 데이터 ꡬ쑰 보쑴
  • λ°˜ν™˜ νƒ€μž…: Stream<R> (R은 λ³€ν™˜λœ νƒ€μž…)

μ˜ˆμ‹œ μ½”λ“œ

// λ¬Έμžμ—΄ 길이 λ³€ν™˜
List<String> words = Arrays.asList("Java", "Stream", "API");
List<Integer> wordLengths = words.stream()
        .map(String::length)
        .collect(Collectors.toList());
// κ²°κ³Ό: [4, 6, 3]
// 객체 λ³€ν™˜
List<User> users = getUserList();
List<String> userNames = users.stream()
        .map(User::getName)
        .collect(Collectors.toList());

2. flatMap() 

 

<R> Stream<R> flatMap(
        Function<? super T,    // T : μž…λ ₯ νƒ€μž… (원본 슀트림의 μš”μ†Œ νƒ€μž…)
        ? extends Stream<? extends R>> mapper // R : 좜λ ₯ νƒ€μž… (μƒˆλ‘œμš΄ 슀트림의 μš”μ†Œ νƒ€μž…)
)

flatMap()은 μ€‘μ²©λœ 슀트림 ꡬ쑰λ₯Ό 단일 레벨둜 ν‰λ©΄ν™”ν•˜λ©΄μ„œ λ³€ν™˜ν•˜λŠ” μž‘μ—…μ„ μˆ˜ν–‰ν•œλ‹€. 각 μš”μ†Œλ₯Ό 슀트림으둜 λ³€ν™˜ν•œ ν›„, ν•˜λ‚˜μ˜ 슀트림으둜 λ³‘ν•©ν•œλ‹€.

μ£Όμš” νŠΉμ§•

  • 쀑첩 ꡬ쑰λ₯Ό 단일 레벨둜 평면화
  • μš”μ†Œλ₯Ό 0개 μ΄μƒμ˜ μš”μ†Œλ‘œ λ³€ν™˜ κ°€λŠ₯ (one-to-many)
  • μ»¬λ ‰μ…˜μ˜ 계측 ꡬ쑰 제거
  • λ°˜ν™˜ νƒ€μž…: Stream<R> (μ€‘μ²©λœ μŠ€νŠΈλ¦Όμ„ 단일 슀트림으둜 λ³€ν™˜)

 

  • κ°’ 생성 방법
    • 0개 κ°’ λ°˜ν™˜: Stream.empty()
    • μ—¬λŸ¬ κ°’ λ°˜ν™˜: Stream.of(a, b, c)

 

Stream<List<Integer>> νƒ€μž…μ˜ numbers.stream()을 flatMap을 μ‚¬μš©ν•΄ Stream<Integer>둜 λ³€ν™˜ ν›„ 리슀트둜 λ°˜ν™˜.

flatMap은 각 μž…λ ₯값에 따라 λ‹€λ₯Έ 개수λ₯Ό λ°˜ν™˜ν•˜λŠ” μœ μ—°ν•œ μ²˜λ¦¬λ„ κ°€λŠ₯ν•˜λ‹€.

class User {
    private String name;
    private List<String> emails;
    // getters, setters...
}

List<String> allEmails = users.stream()
        .flatMap(user -> user.getEmails().stream())
        .collect(Collectors.toList());

μœ„ μ½”λ“œμ—μ„œλŠ” λͺ¨λ“  email 좜λ ₯을 μœ„ν•΄ 각 User별 email이 각자의 리슀트둜 κ΅¬λ³„λ˜μ–΄ email이 좜λ ₯λ˜μ§€ μ•Šκ³  λͺ¨λ“  email을 ν•˜λ‚˜μ˜ 리슀트둜 μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ flatMap을 μ‚¬μš©ν•˜μ˜€λ‹€.

 

3. μ‹€μ œ ν™œμš© 사둀

class Order {
    private List<Product> products;
    // getters, setters...
}

class Product {
    private String name;
    private double price;
    // getters, setters...
}

// λͺ¨λ“  주문의 총 κΈˆμ•‘ 계산
double totalValue = orders.stream()
        .flatMap(order -> order.getProducts().stream())
        .mapToDouble(Product::getPrice)
        .sum();

// λͺ¨λ“  μ œν’ˆ 이름 μΆ”μΆœ
List<String> productNames = orders.stream()
        .flatMap(order -> order.getProducts().stream())
        .map(Product::getName)
        .distinct()
        .collect(Collectors.toList());

μ΄λ ‡κ²Œ 각 μ£Όλ¬Έμ΄λ‚˜ μ œν’ˆ 별이 μ•„λ‹Œ 전체적인 ν†΅κ³„λ‚˜ ν’ˆλͺ©μ„ μΆ”μΆœν•˜κ³  싢은 경우 flatMap이 κ°•λ ₯ν•œ 도ꡬ가 λœλ‹€.

 

 

728x90