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


当前回答

我不太确定我是否应该回答这个问题,但每当我面对不理解这一点的人时,我就用同样的例子。

假设你有一个苹果。例如,地图是将苹果转换为苹果汁或一对一映射。

同样的苹果,只得到种子,这就是flatMap所做的,或者一对多,一个苹果作为输入,许多种子作为输出。

其他回答

简单的答案。

映射操作可以生成流的流。前流<流<整数> >

flatMap操作只会产生流。前流<整数>

对于Map,我们有一个元素列表和一个(函数,动作)f,这样:

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

对于平面映射,我们有一个元素列表,我们有一个(function,action) f,我们希望结果是扁平的:

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

如果您认为map()是一个迭代(一级for循环),那么flatmap()是一个两级迭代(类似于嵌套的for循环)。(输入每个迭代元素foo,然后执行foo. getbarlist()并再次迭代该barList)


Map():获取一个流,对每个元素做一些事情,收集每个进程的单个结果,输出另一个流。“做一些函数”的定义是隐含的。如果任何元素的处理结果为null,则使用null来组成最终流。因此,结果流中的元素数量将等于输入流的数量。

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

Oracle关于Optional的文章强调了map和flatmap的区别:

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

Unfortunately, this code doesn't compile. Why? The variable computer is of type Optional<Computer>, so it is perfectly correct to call the map method. However, getSoundcard() returns an object of type Optional. This means the result of the map operation is an object of type Optional<Optional<Soundcard>>. As a result, the call to getUSB() is invalid because the outermost Optional contains as its value another Optional, which of course doesn't support the getUSB() method. With streams, the flatMap method takes a function as an argument, which returns another stream. This function is applied to each element of a stream, which would result in a stream of streams. However, flatMap has the effect of replacing each generated stream by the contents of that stream. In other words, all the separate streams that are generated by the function get amalgamated or "flattened" into one single stream. What we want here is something similar, but we want to "flatten" a two-level Optional into one. Optional also supports a flatMap method. Its purpose is to apply the transformation function on the value of an Optional (just like the map operation does) and then flatten the resulting two-level Optional into a single one. So, to make our code correct, we need to rewrite it as follows using flatMap:

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

第一个flatMap确保返回Optional<Soundcard> 而不是一个Optional<Optional<Soundcard>>,和第二个flatMap 实现相同的目的,返回Optional<USB>。注意 第三个调用只需要一个map(),因为getVersion()返回一个 字符串而不是可选对象。

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

流。flatMap,顾名思义,是映射和平面操作的组合。这意味着您首先将一个函数应用到元素上,然后将其压平。流。Map仅将函数应用于流,而不会将流平展。

为了理解流的扁平化是由什么组成的,考虑一个像[[1,2,3],[4,5,6],[7,8,9]]这样的结构,它有“两个层次”。扁平化意味着将其转换为“一级”结构:[1,2,3,4,5,6,7,8,9]。