Java 8에서 map ()과 flatMap () 메소드의 차이점은 무엇입니까?


705

Java 8에서 Stream.map()Stream.flatMap()메소드 의 차이점은 무엇 입니까?


55
형식 서명은 전체 이야기를 알려줍니다. map :: Stream T -> (T -> R) -> Stream R, flatMap :: Stream T -> (T -> Stream R) -> Stream R.
Chris Martin

98
그러나 이러한 유형 서명은 Java처럼 보이지 않습니다. (나는 알고있다. 그러나 "전체 이야기"라고 말하면 wrt map / flatMap은 새로운 & 개선 된 "Java ++"에 대해 많은 지식을 가지고 있다고 가정한다)
michael

16
@michael 그 형식 서명은 Java가 아닌 Haskell과 같습니다. 그러나 실제 Java 서명이 더 읽기 쉬운 지 확실하지 않습니다 <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper).
스튜어트 마크

7
하, 그래, 나는 "실제 Java"를 언급하고 있었다. C ++과 마찬가지로 현대 Java는 90 년대에 Java를 사용하기 시작한 모든 사람에게 거의 인식 할 수 없습니다 (두 언어 모두). 단지 의견에 답하기 만하면, 메소드 서명은 추가 설명없이 (또는 그 주석가의 경우 번역이 아닌) 더 이상 "전체 이야기"를 거의 말하지 않습니다.
마이클

2
A, 말을하는 것입니다 어떤 map의 매퍼 람다 반환 R하는 flatMap에 '의 매퍼 람다 반환 StreamR( Stream<R>). flatMap의 매퍼가 반환 한 스트림 은 효과적으로 연결됩니다. 그렇지 않으면, 모두 mapflatMap반환 Stream<R>; 차이는 매퍼 람다가 반환 것입니다 RStream<R>.
derekm

답변:


814

모두 mapflatMapA를 적용 할 수 Stream<T>및 수익 a를 둘 Stream<R>. 차이점은 map연산이 각 입력 값에 대해 하나의 출력 값을 flatMap생성하는 반면, 연산은 각 입력 값에 대해 임의의 숫자 (0 이상) 값을 생성한다는 것입니다.

이는 각 작업에 대한 인수에 반영됩니다.

map연산은 Function입력 스트림의 각 값에 대해 호출되는 하나의 결과 값을 생성하여 출력 스트림으로 전송합니다.

flatMap동작을 개념적으로 하나 개의 값을 소비 값의 임의의 수를 생성하기 원하는 기능 걸린다. 그러나 Java에서는 메소드가 0 또는 하나의 값만 리턴 할 수 있으므로 메소드가 임의의 수의 값을 리턴하는 것은 번거 롭습니다. 매퍼 함수 flatMap가 값 을 가져 와서 배열 또는 배열을 반환하는 API를 상상할 수 있습니다 .List값으로 설정되어 출력으로 전송됩니다. 이것이 스트림 라이브러리라는 점을 감안할 때, 임의의 수의 반환 값을 나타내는 적절한 방법은 매퍼 함수 자체가 스트림을 반환하는 것입니다! 매퍼가 반환 한 스트림의 값은 스트림에서 배출되어 출력 스트림으로 전달됩니다. 매퍼 함수에 대한 각 호출에 의해 리턴 된 값의 "클럼프"는 출력 스트림에서 전혀 구별되지 않으므로 출력이 "평평하게"있다고합니다.

일반적으로 0 값을 보내려는 경우 또는 여러 값을 반환하려는 경우 flatMap반환 하는 매퍼 함수가 사용 됩니다. 물론 모든 스트림을 반환 할 수 있습니다.Stream.empty()Stream.of(a, b, c)


26
flatMap작업이 플랫과 정반대 인 것처럼 들립니다. 그러나 다시 한 번 컴퓨터 과학자에게 맡겨 두어 용어를 바꾸십시오. "투명한"기능을 의미하는 것처럼, 결과를 볼 수없고 구어체 적으로 프로세스를 투명하게하고 싶다고 말하면 모든 부분을 볼 수 있습니다.
coladict

45
@coladict 다른 관점에서 보아보십시오. 내부 작업을 볼 수있는 투명한 경우는 아니지만 전체 기능 자체가 투명합니다. 다시 작업 해보세요. 이 경우 "플랫"은 "중첩"의 반대를 나타내며, 플랫 맵은 병합하여 하나의 중첩 레벨을 제거합니다.
Zefiro

7
@coladict "투명한"것은 몇 년 동안 내 머리를 먹었습니다. 적어도 한 사람이 같은 방식으로 느끼게되어 기쁘다.
Ashok Bijoy Debnath

9
평탄화는 2 레벨 구조를 단일 레벨 구조로 전환하는 데 있습니다. 예는 stackoverflow.com/a/26684582/6012102
andrzej.szmukala의

26
이것이 flatMap 의 가장 좋은 설명입니다 . 이것이 모두 클릭되는 이유입니다 . 매퍼가 반환 한 스트림의 값이 스트림에서 배출되어 출력 스트림으로 전달됩니다. 매퍼 함수에 대한 각 호출에 의해 리턴 된 값의 "클럼프"는 출력 스트림에서 전혀 구별되지 않으므로 출력은 "평 평화"되었다고 합니다. 감사합니다!
neevek

464

Stream.flatMap이름에서 알 수 있듯이 a mapflat연산 의 조합입니다 . 즉, 먼저 요소에 함수를 적용한 다음 평평하게합니다. Stream.map스트림을 평탄화하지 않고 스트림에만 함수를 적용합니다.

스트림의 평탄화 가 무엇인지 이해하려면 [ [1,2,3],[4,5,6],[7,8,9] ]"2 레벨" 과 같은 구조를 고려하십시오 . 이를 평탄화한다는 것은 "한 수준"구조로 변환하는 것을 의미합니다 [ 1,2,3,4,5,6,7,8,9 ].


5
간단하고 달콤한
bluelurker

3
하하, 공정하게도이 질문이 얼마나 많은 트래픽을 받는지보고 놀랐습니다. 또 다른 재밌는 관찰은이 답변을 쓴 지 거의 5 년이되었으며 허용되는 답변이 내 답변이 도착할 때마다 대략 2 개의 공감대를 얻는 상당히 일관된 공감 패턴이 있다는 것입니다. 놀랍게도 일관성이 있습니다.
Dici

1
어떻게 대답이 받아 들여지지
않습니까

233

좀 더 실용적인 관점 을 얻기 위해 두 가지 예를 제시하고 싶습니다
.

@Test
public void convertStringToUpperCaseStreams() {
    List<String> collected = Stream.of("a", "b", "hello") // Stream of String 
            .map(String::toUpperCase) // Returns a stream consisting of the results of applying the given function to the elements of this stream.
            .collect(Collectors.toList());
    assertEquals(asList("A", "B", "HELLO"), collected);
}   

첫 번째 예에서 특별한 것은 없지만 대문자 Function를 반환하는 데 적용됩니다 String.

다음을 사용하는 두 번째 예 flatMap:

@Test
public void testflatMap() throws Exception {
    List<Integer> together = Stream.of(asList(1, 2), asList(3, 4)) // Stream of List<Integer>
            .flatMap(List::stream)
            .map(integer -> integer + 1)
            .collect(Collectors.toList());
    assertEquals(asList(2, 3, 4, 5), together);
}

두 번째 예에서는 Stream of List가 전달됩니다. 정수 스트림이 아닙니다!
변환 기능을 사용해야하는 경우 (맵을 통해) 먼저 스트림을 다른 것 (정수 스트림)으로 평면화해야합니다.
flatMap이 제거되면 다음 오류가 리턴됩니다. 연산자 +는 인수 유형 List, int에 대해 정의되지 않았습니다.
정수 목록에 + 1을 적용 할 수 없습니다!


@PrashanthDebbadwar 나는 스트림이 Stream<Integer>아닌 스트림으로 끝날 것이라고 생각합니다 Integer.
payne

166

명확한 아이디어를 얻으려면 게시물을 완전히 살펴보십시오.

지도 대 평면지도 :

목록에서 각 단어의 길이를 반환하려면 다음과 같이하십시오.

아래에 주어진 짧은 버전

아래에 주어진 두 목록을 수집 할 때

플랫 맵이 없는 경우 => [1,2], [1,1] => [[1,2], [1,1]] 여기에 두 개의 목록이 목록에 배치되므로 목록이 포함 된 목록이 출력됩니다.

함께 평면지도 => [1,2], [1,1] => [1,2,1,1] 다음 두 개의리스트가 평평하고 출력 요소만을 포함하는리스트 수 있도록 값만이리스트에 배치되고

기본적으로 모든 객체를 하나로 병합합니다.

자세한 내용은 다음과 같습니다.

예를 들면 : -은
목록 고려 [ "스택", "OOOVVVER을"] 우리는 같은 목록을 반환하려고하는 [ "STACKOVER은"] 을 다시 보려면 아래처럼, 우리는 무언가를 할 것이다 처음에 (그 목록에서만 고유 한 문자를 반환를) 목록 [ "STACKOVER"] 에서 [ "STACK", "OOOVVVER"]

public class WordMap {
  public static void main(String[] args) {
    List<String> lst = Arrays.asList("STACK","OOOVER");
    lst.stream().map(w->w.split("")).distinct().collect(Collectors.toList());
  }
}

여기서 문제는 map 메서드에 전달 된 Lambda가 각 단어에 대해 String 배열을 반환하므로 map 메서드에 의해 반환 된 스트림은 실제로 Stream 유형입니다. 그러나 필요한 것은 스트림 아래에 문자 스트림을 나타내는 Stream입니다. 문제.

그림 A :

여기에 이미지 설명을 입력하십시오

당신은 그 생각, 우리는 flatmap를 사용하여이 문제를 해결할 수 있습니다,
OK, 우리가 사용하여이 문제를 해결하는 방법을 볼 수 있도록 지도 하고 Arrays.stream 대신 배열의 스트림의 문자의 스트림을 필요거야 우선합니다. 배열을 가져와 스트림을 생성하는 Arrays.stream ()이라는 메서드가 있습니다. 예를 들면 다음과 같습니다.

String[] arrayOfWords = {"STACK", "OOOVVVER"};
Stream<String> streamOfWords = Arrays.stream(arrayOfWords);
streamOfWords.map(s->s.split("")) //Converting word in to array of letters
    .map(Arrays::stream).distinct() //Make array in to separate stream
    .collect(Collectors.toList());

우리는 이제 스트림 목록 (더 정확하게 말하면 Stream>)으로 끝나기 때문에 여전히 작동하지 않습니다. 대신 먼저 각 단어를 개별 문자 배열로 변환 한 다음 각 배열을 별도의 스트림으로 만들어야합니다

flatMap을 사용하면 다음과 같이이 문제를 해결할 수 있습니다.

String[] arrayOfWords = {"STACK", "OOOVVVER"};
Stream<String> streamOfWords = Arrays.stream(arrayOfWords);
streamOfWords.map(s->s.split("")) //Converting word in to array of letters
    .flatMap(Arrays::stream).distinct() //flattens each generated stream in to a single stream
    .collect(Collectors.toList());

flatMap은 스트림이 아니라 해당 스트림의 내용으로 각 배열을 매핑합니다. map (Arrays :: stream)을 사용하는 동안 생성되는 모든 개별 스트림은 단일 스트림으로 병합됩니다. 그림 B는 flatMap 메소드 사용의 효과를 보여줍니다. 그림 A의지도와 비교해보십시오. 그림 B 여기에 이미지 설명을 입력하십시오

flatMap 메소드를 사용하면 스트림의 각 값을 다른 스트림으로 교체 한 다음 생성 된 모든 스트림을 단일 스트림으로 결합 할 수 있습니다.


2
좋은 도식 설명.
Hitesh

107

한 줄로 답변 : flatMapa Collection<Collection<T>>로 평평하게하는 데 도움이됩니다Collection<T> . 같은 방식으로, 또한 평평하게됩니다 Optional<Optional<T>>에를 Optional<T>.

여기에 이미지 설명을 입력하십시오

로서 당신은, 볼에 수 map()만 :

  • 중간 유형은 Stream<List<Item>>
  • 반품 유형은 List<List<Item>>

와 함께 flatMap():

  • 중간 유형은 Stream<Item>
  • 반품 유형은 List<Item>

이것은 바로 아래에 사용 된 코드 의 테스트 결과 입니다.

-------- Without flatMap() -------------------------------
     collect() returns: [[Laptop, Phone], [Mouse, Keyboard]]

-------- With flatMap() ----------------------------------
     collect() returns: [Laptop, Phone, Mouse, Keyboard]

사용 된 코드 :

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public class Parcel {
  String name;
  List<String> items;

  public Parcel(String name, String... items) {
    this.name = name;
    this.items = Arrays.asList(items);
  }

  public List<String> getItems() {
    return items;
  }

  public static void main(String[] args) {
    Parcel amazon = new Parcel("amazon", "Laptop", "Phone");
    Parcel ebay = new Parcel("ebay", "Mouse", "Keyboard");
    List<Parcel> parcels = Arrays.asList(amazon, ebay);

    System.out.println("-------- Without flatMap() ---------------------------");
    List<List<String>> mapReturn = parcels.stream()
      .map(Parcel::getItems)
      .collect(Collectors.toList());
    System.out.println("\t collect() returns: " + mapReturn);

    System.out.println("\n-------- With flatMap() ------------------------------");
    List<String> flatMapReturn = parcels.stream()
      .map(Parcel::getItems)
      .flatMap(Collection::stream)
      .collect(Collectors.toList());
    System.out.println("\t collect() returns: " + flatMapReturn);
  }
}

8
예를 들어 개념을 이해하는 데 몇 초 이상 걸리지 않을 것입니다.
TechDog

2
좋은 설명입니다. 간단하고 최상의 설명을 주셔서 감사합니다
Sachin Rane

42

전달하는 함수 stream.map는 하나의 객체를 반환해야합니다. 즉, 입력 스트림의 각 객체는 출력 스트림에서 정확히 하나의 객체가됩니다.

전달하는 stream.flatMap함수는 각 객체에 대한 스트림 을 반환합니다. 즉, 함수는 각 입력 개체에 대해 여러 개체를 반환 할 수 있습니다 (없음 포함). 결과 스트림은 하나의 출력 스트림에 연결됩니다.


왜 "각 입력 개체 (없음 포함)에 대해 여러 개체를 반환 하시겠습니까?"
Derek Mahar

4
@DerekMahar 이것에 대한 많은 유스 케이스가있을 것입니다. 예를 들어 Department조직에 스트림이 있다고 가정 해 봅시다 . 각 부서는 0과 n 사이 Employee입니다. 필요한 것은 모든 직원의 흐름입니다. 그래서 당신은 무엇을합니까? 부서를 가져와 직원 스트림을 리턴하는 flatMap 메소드를 작성하십시오.
Philipp

필립, 당신의 모범은 사용해야하는 주된 이유를 보여 flatMap줍니까? 부수적 일 수 있으며 주요 사용 사례 또는 이유가 flatMap존재 하지 않는 것으로 의심 됩니다. (... 아래에 계속)
데릭 Mahar에게

dzone.com/articles/understanding-flatmap을 읽은 후 뒤에 사용 된 주요 flatMap오류는 사용시 발생할 수있는 오류를 수용하는 것 map입니다. 원본 세트의 하나 이상의 항목을 출력 항목에 매핑 할 수없는 경우를 어떻게 처리합니까? 각 입력 개체에 대해 중간 집합 (예 : Optional또는 Stream)을 도입하면 flatMap"유효하지 않은"입력 개체 (또는 stackoverflow.com/a/52248643/107158 의 정신에서 "나쁜 사과")를 제외 할 수 있습니다 . 최종 세트.
Derek Mahar

1
@DerekMahar 예, 각 입력 개체가 출력 개체를 반환하거나 반환하지 않을 수있는 개념은 플랫 맵의 또 다른 유용한 사용 사례입니다.
Philipp

29

Map의 경우 요소 목록과 (함수, 동작) f가 있습니다.

[a,b,c] f(x) => [f(a),f(b),f(c)]

평평한 맵의 경우 요소 목록이 있고 (함수, 동작) f가 있으며 결과를 평평하게하고 싶습니다.

[[a,b],[c,d,e]] f(x) =>[f(a),f(b),f(c),f(d),f(e)]

25

나는 대부분의 대답이 간단한 문제를 너무 복잡하게 생각합니다. map상당히 이해하기 쉬운 작품을 이미 이해하고 있다면 .

를 사용할 때 원하지 않는 중첩 구조로 끝날 수있는 경우가 있습니다 map().이 flatMap()방법은 줄 바꿈을 피함으로써이를 극복하도록 설계되었습니다.


예 :

1

List<List<Integer>> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
  .collect(Collectors.toList());

다음을 사용하여 중첩 목록을 피할 수 있습니다 flatMap.

List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
  .flatMap(i -> i.stream())
  .collect(Collectors.toList());

2

Optional<Optional<String>> result = Optional.of(42)
      .map(id -> findById(id));

Optional<String> result = Optional.of(42)
      .flatMap(id -> findById(id));

어디:

private Optional<String> findById(Integer id)

죄송하지만 포인트 1의 두 번째 스 니펫이 대신 컴파일되지 않습니다 List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(i -> i) .collect(Collectors.toList());. 그것은이어야한다Stream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(List::stream) .collect(Collectors.toList());
arthur

@arthur 내가 여기 Vavr의 스트림과 목록을 사용 생각 -하지만 난 그것을 조금 혼동 될 수 있음을 동의합니다 - 내가 표준 자바에 그 변경됩니다
그르 Piwowarek

@GrzegorzPiwowarek 이 간단한 설명은 어떻습니까?
유진

22

Optional에 관한 오라클의 기사는 맵과 플랫 맵의 차이점을 강조합니다.

String version = computer.map(Computer::getSoundcard)
                  .map(Soundcard::getUSB)
                  .map(USB::getVersion)
                  .orElse("UNKNOWN");

불행히도이 코드는 컴파일되지 않습니다. 왜? 가변 컴퓨터는 유형 Optional<Computer>이므로 map 메소드를 호출하는 것이 완벽합니다. 그러나 getSoundcard ()는 Optional 유형의 객체를 반환합니다. 이는 맵 조작의 결과가 유형의 오브젝트임을 의미합니다 Optional<Optional<Soundcard>>. 결과적으로 getUSB () 호출은 유효하지 않습니다. 가장 바깥 쪽 Optional에는 다른 Optional 값이 포함되어 있기 때문에 유효하지 않습니다. 물론 getUSB () 메서드를 지원하지 않습니다.

스트림의 경우 flatMap 메소드는 함수를 인수로 사용하여 다른 스트림을 리턴합니다. 이 함수는 스트림의 각 요소에 적용되어 스트림 스트림을 생성합니다. 그러나 flatMap은 생성 된 각 스트림을 해당 스트림의 내용으로 바꾸는 효과가 있습니다. 다시 말해, 함수에 의해 생성 된 모든 개별 스트림은 하나의 단일 스트림으로 통합되거나 "평탄화"됩니다. 여기서 우리가 원하는 것은 비슷하지만, 2- 레벨 옵션을 하나로 "평평하게"하고 싶습니다 .

선택 사항은 flatMap 메소드도 지원합니다. 그 목적은 (맵 연산과 마찬가지로) Optional 값에 변환 함수를 적용한 다음 결과적인 2 단계 Optional을 단일 항목으로 병합하는 것 입니다.

따라서 코드를 올바르게 작성하려면 flatMap을 사용하여 다음과 같이 코드를 다시 작성해야합니다.

String version = computer.flatMap(Computer::getSoundcard)
                   .flatMap(Soundcard::getUSB)
                   .map(USB::getVersion)
                   .orElse("UNKNOWN");

첫 번째 flatMap은을 Optional<Soundcard>대신 하여 a 가 반환 되도록하고 두 번째 flatMap은을 반환 Optional<Optional<Soundcard>>하는 동일한 목적을 달성합니다 Optional<USB>. getVersion ()은 Optional 객체가 아닌 String을 반환하므로 세 번째 호출은 map ()이어야합니다.

http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html


1
문제는 Stream.map과 Stream.flatMap에 관한 것이지 & Optional.map에 관한 것이 아니라 anfd Optional.flatMap
djames

4
그러나 옵션 및 플랫 맵 관련 문제를 이해하는 데 많은 도움이되었습니다.
Loïc

2
@djames, 그것은 완벽하게 유효한 대답이다 :) "... flatMap 방법은 함수를 인수로 취, 스트림과 함께"이 단락부터 읽기
skwisgaar

나는 이것이 다른 답변들에 매우 유용한 추가라고 생각합니다.
Mz A

soundCard가 null 인 경우 flatMap () 버전도 nullpointerException을 throw합니다. 옵션의 약속 된 이점은 어디에 있습니까?
Ekaterina

16

나는 이것에 대답해야한다고 확신하지 못하지만, 이것을 이해하지 못하는 사람을 만날 때마다 동일한 예를 사용합니다.

사과가 있다고 상상해보십시오. A map는 그 사과를 apple-juice예를 들어 또는 일대일 매핑으로 변환하고 있습니다.

같은 사과를 꺼내서 씨앗을 꺼냅니다. 즉 flatMap, 일대 다 , 사과는 입력으로, 씨앗은 많은 것으로 산출합니다.


4
흥미로운 예입니다 :)
cassiomolin

flatMap경우, 모든 가방을 한 봉지에 넣기 전에 먼저 각 사과에서 씨앗을 개별 봉지 (사과 당 한 봉지)에 모으십니까?
Derek Mahar

이 자바-10 전에 하나의 가방에 가난한로 사용 @DerekMahar, 의미는 flatmap정말 게으른 아니었지만, 자바-10 이후는 게으른
유진

@ Eugene은 나에게 명확하지 않은 설명을하려고하는 좀 더 게으른 개념을 설명하십시오 .derkerMahar가 주석에서 설명 한 것이 Java10 이전에 일어난 일이라는 것을 이해 했습니까?
JAVA

@ JAVA 그냥 검색 flatMap + lazy, 나는 대답이있을 것입니다 내기.
Eugene

16

map () 및 flatMap ()

  1. map()

T는 element이고 R은 return element를 사용하여 람다 매개 변수를 함수로 가져옵니다. 마지막에는 Type R의 객체가있는 Stream이 있습니다. 간단한 예는 다음과 같습니다.

Stream
  .of(1,2,3,4,5)
  .map(myInt -> "preFix_"+myInt)
  .forEach(System.out::println);

단순히 Type의 1 ~ 5 요소를 가져 와서 Integer각 요소를 사용 String하여 값 으로 type에서 새 요소를 작성 "prefix_"+integer_value하고 인쇄합니다.

  1. flatMap()

flatMap () 함수 F<T, R>

  • T는 에서 /으로 스트림을 빌드 할 수 있는 유형 입니다 . List (T.stream ()), Array (Arrays.stream (someArray)) 등이 될 수 있습니다. 아래 예제에서 각 개발자는 많은 언어를 가지고 있으므로 dev. 언어는 목록이며 람다 매개 변수를 사용합니다.

  • R은 T를 사용하여 빌드되는 결과 스트림입니다. T의 인스턴스가 많음을 알면 당연히 R의 스트림이 많이 있습니다. 유형 R의 모든 스트림은 이제 유형 R의 단일 '플랫'스트림 으로 결합됩니다. .

Bachiri Taoufiq의 예는 여기대한 대답 이 간단하고 이해하기 쉽다는 것을 알 수 있습니다. 명확성을 위해 개발자 팀이 있다고 가정 해 보겠습니다.

dev_team = {dev_1,dev_2,dev_3}

, 각 개발자는 여러 언어를 알고 있습니다.

dev_1 = {lang_a,lang_b,lang_c},
dev_2 = {lang_d},
dev_2 = {lang_e,lang_f}

dev_team에 Stream.map () 을 적용 하여 각 개발자의 언어를 가져옵니다.

dev_team.map(dev -> dev.getLanguages())

이 구조를 제공합니다 :

{ 
  {lang_a,lang_b,lang_c},
  {lang_d},
  {lang_e,lang_f}
}

기본적으로 List<List<Languages>> /Object[Languages[]]. 별로 예쁘지도 않고 Java8과 비슷합니다!

으로 Stream.flatMap()는 상기 구조 걸리는대로 일을 '평평'수
와에 회전을 {lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}기본적으로 사용 할 수 있습니다 List<Languages>/Language[]/etc...

결국 코드는 다음과 같이 더 의미가 있습니다.

dev_team
   .stream()    /* {dev_1,dev_2,dev_3} */
   .map(dev -> dev.getLanguages()) /* {{lang_a,...,lang_c},{lang_d}{lang_e,lang_f}}} */
   .flatMap(languages ->  languages.stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
   .doWhateverWithYourNewStreamHere();

또는 간단히 :

dev_team
       .stream()    /* {dev_1,dev_2,dev_3} */
       .flatMap(dev -> dev.getLanguages().stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
       .doWhateverWithYourNewStreamHere();

map ()을 사용하고 flatMap ()을 사용하는 경우 :

  • map()스트림에서 T 유형의 각 요소가 R 유형 의 단일 요소에 맵핑 / 변환되어야하는 경우에 사용하십시오 . 결과는 유형 (1 시작 요소-> 1 끝 요소) 의 맵핑 과 R 유형의 요소의 새 스트림입니다. 반환됩니다.

  • flatMap()스트림에서 T 유형의 각 요소가 R 유형의 요소 콜렉션 에 맵핑 / 변환 될 때 사용 됩니다 . 결과는 유형의 맵핑입니다 (1 시작 요소-> n 끝 요소) . 그런 다음이 컬렉션은 R 유형의 새로운 요소 스트림에 병합 (또는 병합 )됩니다. 예를 들어 중첩 루프 를 나타내는 데 유용합니다 .

프리 자바 8 :

List<Foo> myFoos = new ArrayList<Foo>();
    for(Foo foo: myFoos){
        for(Bar bar:  foo.getMyBars()){
            System.out.println(bar.getMyName());
        }
    }

포스트 자바 8

myFoos
    .stream()
    .flatMap(foo -> foo.getMyBars().stream())
    .forEach(bar -> System.out.println(bar.getMyName()));

11

Map :-이 메소드는 하나의 함수를 인수로 사용하여 전달 된 함수를 스트림의 모든 요소에 적용하여 생성 된 결과로 구성된 새 스트림을 리턴합니다.

정수 값 (1,2,3,4,5) 목록과 논리가 전달 된 정수의 제곱 인 함수 인터페이스가 있다고 가정 해 봅시다. (e-> e * e).

List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5);

List<Integer> newList = intList.stream().map( e -> e * e ).collect(Collectors.toList());

System.out.println(newList);

산출:-

[1, 4, 9, 16, 25]

보다시피, 출력은 값이 입력 스트림의 제곱 값인 새로운 스트림입니다.

[1, 2, 3, 4, 5] -> apply e -> e * e -> [ 1*1, 2*2, 3*3, 4*4, 5*5 ] -> [1, 4, 9, 16, 25 ]

http://codedestine.com/java-8-stream-map-method/

FlatMap :-이 메소드는 하나의 함수를 인수로 사용합니다.이 함수는 하나의 매개 변수 T를 입력 인수로 받아들이고 매개 변수 R의 하나의 스트림을 리턴 값으로 리턴합니다. 이 함수를이 스트림의 각 요소에 적용하면 새로운 값의 스트림이 생성됩니다. 그런 다음 각 요소에 의해 생성 된 이러한 새 스트림의 모든 요소가 새 스트림으로 복사되며이 스트림은이 메소드의 리턴 값입니다.

이미지를 보도록하겠습니다. 각 학생이 여러 과목을 선택할 수있는 학생 대상 목록이 있습니다.

List<Student> studentList = new ArrayList<Student>();

  studentList.add(new Student("Robert","5st grade", Arrays.asList(new String[]{"history","math","geography"})));
  studentList.add(new Student("Martin","8st grade", Arrays.asList(new String[]{"economics","biology"})));
  studentList.add(new Student("Robert","9st grade", Arrays.asList(new String[]{"science","math"})));

  Set<Student> courses = studentList.stream().flatMap( e -> e.getCourse().stream()).collect(Collectors.toSet());

  System.out.println(courses);

산출:-

[economics, biology, geography, science, history, math]

보시다시피, 출력은 값이 입력 스트림의 각 요소에 의해 반환되는 스트림의 모든 요소의 모음 인 새 스트림입니다.

[S1, S2, S3]-> [{ "역사", "수학", "지리학"}, { "경제학", "생물학"}, { "과학", "수학"}]-> 고유 한 과목 수강- > [경제학, 생물학, 지리학, 과학, 역사, 수학]

http://codedestine.com/java-8-stream-flatmap-method/


단순히 문서 링크를 제공하는 대신 코드를 제공하면 차이를 만들 수 있습니다
Charles-Antoine Fournel

11

.mapA-> B 매핑 용입니다.

Stream.of("dog", "cat")              // stream of 2 Strings
    .map(s -> s.length())            // stream of 2 Integers: [3, 3]

모든 항목 A을 모든 항목으로 변환합니다 B. 자바 독


.flatMap을 위한 A -> 스트림 <B> concatinating

Stream.of("dog", "cat")             // stream of 2 Strings
    .flatMapToInt(s -> s.chars())   // stream of 6 ints:      [d, o, g, c, a, t]

--1은 모든 항목을 A로 변환 Stream< B>한 다음 –2는 모든 스트림을 하나의 (평평한) 스트림으로 연결합니다. 자바 독


참고 1 : 후자의 예제는 객체 스트림 (Stream) 대신 프리미티브 스트림 (IntStream)으로 전개되지만 여전히 아이디어를 보여줍니다 .flatMap.

참고 2 : 이름에도 불구하고 String.chars () 메서드는 정수를 반환합니다. 실제 수집 될 수 있도록 : [100, 111, 103, 99, 97, 116] 여기서 100의 코드이며 'd', 111의 코드 'o'등 다시, 예시의 목적을 위해, 그것은 [D, O, G, C, A, t]로서 제시합니다.


3
가장 좋은 답변입니다. 예를 가진 점에 직선
GabrielBB

1

간단한 대답.

map동작은 생산할 수 StreamStream.EX을Stream<Stream<Integer>>

flatMap작업은 Stream무언가 만 생성 합니다. 전의Stream<Integer>


0

또한 익숙하다면 C # 과도 유추 할 수 있습니다. 기본적으로 C # Select은 java map및 C # SelectManyjava 와 유사합니다 flatMap. 코 틀린의 컬렉션에도 동일하게 적용됩니다.


0

초보자에게는 매우 혼란 스럽습니다. 기본적인 차이점은 map목록의 각 항목마다 하나의 항목을 내 보내며 flatMap기본적으로 map+ flatten작업입니다. 더 명확하게, 하나 이상의 값이 필요할 때 flatMap을 사용하십시오. 예를 들어, 배열을 리턴하기 위해 루프를 기대할 경우 flatMap이이 경우에 실제로 도움이됩니다.

이에 대한 블로그를 작성했습니다 . 여기에서 확인할 수 있습니다 .



0

작업 스트림 flatMapmap입력 등의 기능을 동의합니다.

flatMap함수는 스트림의 각 요소에 대해 새 스트림을 반환하고 각 요소에 대해 함수가 반환 한 스트림의 모든 요소를 ​​결합하는 스트림을 반환합니다. 다시 말해 flatMap소스의 각 요소에 대해를 사용하면 함수에 의해 여러 요소가 만들어집니다. http://www.zoftino.com/java-stream-examples#flatmap-operation

map함수가 변환 된 값을 리턴하고 변환 된 요소를 포함하는 새 스트림을 리턴합니다. 다시 말해 map소스의 각 요소에 대해를 사용하면 변환 된 요소 하나가 함수에 의해 만들어집니다. http://www.zoftino.com/java-stream-examples#map-operation



0

map()반복 (1 레벨 for루프) 으로 생각 flatmap()하면 중첩 for루프 와 같은 2 레벨 반복 입니다. (각 반복 된 요소를 입력 foo하고, 어떻게 foo.getBarList()그와 반복 처리 barList다시)


map(): 스트림을 가져 와서 모든 요소에 대해 무언가를하고 모든 프로세스의 단일 결과를 수집하고 다른 스트림을 출력합니다. "일부 기능 수행"의 정의는 암시 적입니다. 요소의 처리 결과가 null이면 null최종 스트림을 작성하는 데 사용됩니다. 따라서 결과 스트림의 요소 수는 입력 스트림 수와 같습니다.

flatmap(): 요소 / 스트림의 스트림 과 함수 (명시 적 정의)를 취하여 각 스트림의 각 요소에 함수를 적용하고 모든 중간 결과 스트림을 더 큰 스트림 ( "flattening")으로 수집합니다. 요소의 처리 결과가 null이면 빈 스트림이 "평면화"의 마지막 단계로 제공됩니다. 입력 스트림이 여러 스트림 인 경우 결과 스트림의 요소 수는 모든 입력에 참여하는 모든 요소의 총계입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.