Java 8中的map()和flatMap()方法之间有什么区别?


704

在Java 8中,Stream.map()Stream.flatMap()方法之间有什么区别?


55
类型签名可以说明整个故事。map :: Stream T -> (T -> R) -> Stream RflatMap :: Stream T -> (T -> Stream R) -> Stream R
克里斯·马丁

97
首先,这些类型签名甚至看起来都不像Java。(我知道,我知道-但可以说它讲述了“整个故事”,而wrt map / flatMap则假定了有关新的和改进的“ Java ++”的大量知识)
迈克尔

16
@michael该类型签名看起来像Haskell,而不是Java。但尚不清楚实际的Java签名是否更具可读性:<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
斯图尔特(Stuart Marks)

7
哈,是的,我指的是“实际的Java”。像C ++一样,现代Java对于90年代开始使用它的人几乎是无法识别的(就像我一样,两种语言都一样)。只要回复评论,该方法签名就很难说出“整个故事”,至少在没有其他说明(或者在该评论者的情况下为翻译)的情况下,至少不会。
迈克尔,

2
这就是说,一个map的映射拉姆达的回报R,一个flatMap的映射拉姆达回报StreamRStream<R>)。flatMap的映射器返回的流被有效地连接起来。否则,无论是mapflatMap回报Stream<R>; 区别是映射器lambda返回的结果RStream<R>
derekm,

Answers:


813

双方mapflatMap可以应用到Stream<T>他们都回报Stream<R>。区别在于,该map运算为每个输入值生成一个输出值,而该flatMap运算为每个输入值生成任意数量(零个或多个)的值。

这反映在每个操作的参数中。

map操作采用一个Function,对于输入流中的每个值调用,并产生一个结果值,该结果值发送到输出流。

flatMap操作采用的功能在概念上要消耗一个值并产生任意数量的值。但是,在Java中,方法返回任意数量的值很麻烦,因为方法只能返回零或一个值。可以想象一个API,其中的映射器函数flatMap需要一个值并返回一个数组或一个List值,然后将其发送到输出。既然这是流库,那么表示任意数量的返回值的一种特别合适的方法是使映射器函数本身返回流!映射器返回的流中的值将从流中排出,并传递到输出流。每次对映射器函数的调用返回的值的“聚集”在输出流中根本没有被区分,因此输出被认为是“扁平化的”。

典型的应用是的映射功能flatMap,以回报Stream.empty(),如果要发送零个值,或者类似的东西Stream.of(a, b, c),如果要返回几个值。但是,当然可以返回任何流。


26
在我看来,该flatMap操作与flat完全相反。再一次,将它留给计算机科学家来解决。就像一个函数是“透明的”,意味着您看不到它所做的任何事情,仅是结果,而通俗地说,您希望一个过程透明,意味着您希望它的每个部分都能被看到。
coladict

44
@coladict尝试从不同的角度查看它:这不是透明的情况,您可以通过它看到内部的工作原理,但是整个函数本身对您是透明的(即不可见),同时仍在继续工作并让您看到自己的内容重新合作。在这种情况下,“平面”是指与“嵌套”相反,平面图通过展平移除一个嵌套层。
Zefiro

7
@coladict“透明”的东西已经困扰我很多年了。很高兴知道至少另一个人也有同样的感觉。
Ashok Bijoy Debnath,

9
展平来自于将2级结构转换为单级结构,请参见Dici的答案作为示例stackoverflow.com/a/26684582/6012102
andrzej.szmukala

26
这是flatMap的最佳解释。这就是使它全部被单击的原因:映射器返回的流中的值从流中流失,并传递到输出流。每次对映射器函数的调用返回的值的“聚集”在输出流中根本没有被区分,因此输出被认为是“扁平化的”。谢谢!
neevek

463

Stream.flatMap顾名思义,是a mapflat运算的组合。这意味着您首先要对元素应用一个函数,然后对其进行展平。Stream.map仅将功能应用于流而不会展平流。

要了解使流变平的含义,请考虑[ [1,2,3],[4,5,6],[7,8,9] ]具有“两个级别”的结构。压扁这意味着一个“一平”的结构转变它:[ 1,2,3,4,5,6,7,8,9 ]


5
简单而甜蜜
bluelurker

3
哈哈,老实说,我仍然很惊讶地看到这个问题获得了多少流量。另一个有趣的发现是,我写这个答案已经快5年了,并且有一种相当一致的投票方式,即接受的答案每获得一个答案就获得大约两次投票。这是令人惊讶的一致。
Dici

1
这是不是一个公认的答案,感谢您直截了当并提出一个非常简单的例子
1mike12 '19

233

我想举两个例子以获得实际的观点:
第一个使用map的例子:

@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应用a来返回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展平为其他对象(整数流)。
如果删除了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]时,这里两个列表被展平,并且仅将值放置在列表中,因此输出将是仅包含元素的列表

基本上,它将所有对象合并为一个

##详细版本如下:

例如:-
考虑一个列表[“ STACK”,“ 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解决此问题,
好吧,让我们看看如何使用mapArrays.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

一条答案:flatMap有助于将a展平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将为每个对象返回一个流。这意味着该函数可以为每个输入对象返回任意数量的对象(包括无对象)。然后将生成的流连接到一个输出流。


为什么要“为每个输入对象返回任意数量的对象(包括无对象)”?
德里克·马哈

4
@DerekMahar会有很多用例。例如,假设Department您的组织中有s 个流。每个部门有0到n Employees 之间。您需要的是所有员工流。所以你会怎么做?您编写一个flatMap方法,该方法接受部门并返回其员工流。
菲利普

Philipp,您的示例说明了使用的主要原因flatMap吗?我怀疑这可能是偶然的,没有说明关键的用例或flatMap存在的原因。(下接续...)
德里克·马哈

阅读dzone.com/articles/understanding-flatmap后,我认为其主要动机flatMap是为了适应使用时可能出现的错误map。您如何处理原始集中的一个或多个项目无法映射到输出项目的情况?通过为每个输入对象引入中间集(例如OptionalStream),flatMap可以从中排除“无效”输入对象(或本着stackoverflow.com/a/52248643/107158精神的所谓“坏苹果” )最终集。
德里克·马哈

1
@DerekMahar是的,每个输入对象可能会或可能不会返回输出对象的陈述是平面地图的另一个好用例。
菲利普

29

对于Map,我们有一个元素列表和一个(function,action)f,因此:

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

对于平面地图,我们有一个元素列表list,并且我们有一个(function,action)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我想我在这里使用了Vavr的Stream和List-但我同意这可能会造成一些混乱-我将其更改为标准Java
Grzegorz Piwowarek


22

Oracle在Optional上的文章强调了map和flatmap之间的区别:

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作为其值,该Optional当然不支持getUSB()方法。

对于流,flatMap方法将一个函数作为参数,该函数返回另一个流。此功能应用于流的每个元素,这将导致流的流。但是,flatMap的作用是用该流的内容替换每个生成的流。换句话说,该函数生成的所有单独流都将合并或“压缩”为一个单个流。我们在这里想要的是类似的东西,但是我们想将两个级别的Optional“扁平化”为一个

Optional还支持flatMap方法。其目的是将转换函数应用于Optional的值(就像map操作一样),然后将生成的两层Optional展平为一个

因此,为了使我们的代码正确,我们需要使用flatMap如下重写它:

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

第一个flatMap确保Optional<Soundcard>返回an 而不是an Optional<Optional<Soundcard>>,第二个flatMap达到返回an的相同目的Optional<USB>。注意,第三个调用只需要是一个map(),因为getVersion()返回的是String而不是Optional对象。

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


1
问题是关于Stream.map和Stream.flatMap的,而不是关于Optional.map anfd Optional.flatMap的
djames

4
但这对我了解可选和平面图的问题大有帮助,非常感谢!
卢瓦克

2
@djames,这是一个非常有效的答案,请从“使用流,flatMap方法将函数作为参数...”段落开始阅读:)
skwisgaar

我认为这是对此处其他一些答案的非常有用的补充。
Mz A

如果soundCard为null,则flatMap()版本也会引发nullpointerexception。那么Optional的承诺收益在哪里?

16

我不太确定我应该回答这个问题,但是每次遇到一个不理解这一点的人时,我都会使用相同的示例。

想象你有一个苹果。A map正在将该苹果转换apple-juice为例如一对一映射。

取那个苹果,只取其中的一个种子,就是flatMap这样,或者一对多,一个苹果作为输入,许多种子作为输出。


4
那是一个有趣的例子:)
cassiomolin '18

对于这种flatMap情况,在将所有袋子倒入一个袋子之前,您是否首先将每个苹果的种子收集在单独的袋子中,每个苹果一个袋子?
德里克·马哈

@DerekMahar在Java-10之前曾经很穷,只能装进一个袋子里,这flatmap并不是很懒,但是由于Java-10却很懒
Eugene

@Eugene请解释一个更懒惰的概念,您试图向我解释这个概念。我理解derkerMahar在注释中解释的是在Java10之前发生的事情吗?
JAVA

@JAVA只是搜索flatMap + lazy,我敢肯定会有一些答案。
尤金(Eugene)

16

map()和flatMap()

  1. map()

只需将一个lambda参数作为Function即可,其中T是元素,R是使用T构建的返回元素。最后,我们将获得一个带有R类型对象的Stream。一个简单的示例可以是:

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

它仅Integer使用Type的元素1到5 ,使用每个元素从String具有值的type中构造一个新元素"prefix_"+integer_value并将其打印出来。

  1. flatMap()

知道flatMap()接受一个函数F<T, R>

  • T是一种类型,可以从中使用/来构建Stream。它可以是一个List(T.stream()),一个数组(Arrays.stream(someArray))等。任何Stream可以采用/或采用其形式的形式。在下面的示例中,每个开发人员都有多种语言,因此开发人员。语言是一个列表,将使用lambda参数。

  • 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种开始元素- >Ñ端部元件)。然后这些Collection 合并(或展)为R类型的新元素流。这对于表示嵌套循环很有用。

Java 8之前的版本:

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

Java 8后

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

11

Map:-此方法以一个Function作为参数,并返回一个新流,该流包含通过将传递的函数应用于流的所有元素而生成的结果。

想象一下,我有一个整数值列表(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:-此方法以一个Function作为参数,此函数接受一个参数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

.map用于A-> B映射

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

它将任何项目转换A为任何项目BJava文档


.flatMap用于A-> Stream <B>叠加

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将所有流连接为一个(固定)流。Java文档


注意1:尽管后面的示例简化为原始流(IntStream)而不是对象流(Stream),但仍说明了.flatMap

注意2:尽管有名称,String.chars()方法仍返回int。因此,实际的集合将是:[100, 111, 103, 99, 97, 116] ,其中100的代码是'd'111是等的代码'o'。同样,出于说明目的,将其表示为[d,o,g,c,a,t]。


3
最佳答案。举例说明
GabrielBB

1

简单的答案。

map操作可产生StreamStream.EXStream<Stream<Integer>>

flatMap操作只会产生Stream一些东西。前Stream<Integer>


0

如果您熟悉C#,也可以很好地类比。基本上C#Select类似于java map和C#SelectManyjava flatMap。同样适用于Kotlin进行收藏。


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()视为迭代(一级for循环),flatmap()则是二级迭代(如嵌套for循环)。(输入每个迭代的元素foo,然后foo.getBarList()在其中进行迭代barList


map():获取一个流,对每个元素进行处理,收集每个进程的单个结果,输出另一个流。“执行某项功能”的定义是隐式的。如果任何元素的处理结果为nullnull则用于组成最终流。因此,结果流中的元素数量将等于输入流的数量。

flatmap():获取元素/流和函数(显式定义)的,将函数应用于每个流的每个元素,并将所有中间结果流收集为更大的流(“展平”)。如果任何元素的处理导致null,则将空流提供给“扁平化”的最后步骤。如果输入是多个流,则结果流中元素的数量是所有输入中所有参与元素的总数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.