FunTester Java Stream 中 map 和 flatMap 方法

FunTester · 2020年10月11日 · 920 次阅读

最近看到一篇讲stream语法的文章,学习Javamap()flatMap()方法之间的区别。

虽然看起来这两种方法都做同样的事情,都是做的映射操作,但实际上差之毫厘谬以千里。

通过演示 Demo 中的代码可以了解map()flatMap()的具体功能差异。

  • 首先来一段简单的stream语法foreach方法的用法

演示 Demo:

List<String> funs = Arrays.asList("F", "U", "N");
funs.stream().forEach(x -> output(x));

控制台输出:

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
F
U
N

Process finished with exit code 0

map 方法

map()是一个中间操作,这意味着它返回Stream对象。

  • 先来一个简单

演示 Demo:

List<String> funs = Arrays.asList("F", "U", "N");
funs.stream().map(x->x+"001").forEach(x->output(x));

控制台输出:

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
INFO-> f
INFO-> u
INFO-> n
INFO-> F001
INFO-> U001
INFO-> N001
java.util.stream.ReferencePipeline$3@27ae2fd0
java.util.stream.ReferencePipeline$3@29176cc1

Process finished with exit code 0

  • 再来一个复杂的

演示 Demo:

List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");

List<List<String>> nestedList = Arrays.asList(fun1, fun2);
nestedList.stream().map(x -> {
    return x.stream().map(a -> a.toUpperCase());
}).forEach(x -> output(x));

控制台输出:

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
INFO-> java.util.stream.ReferencePipeline$3@45018215
INFO-> java.util.stream.ReferencePipeline$3@30b7c004

显然,在最后一步输出的时候,x是一个stream的对象,而不是一个list对象。

当我们尝试从List<List<String>>获取值进行操作时,map()无法如预期一样工作,需要进行修改才能从嵌套的List<List<String>>对象获取字符串值。

如下:

List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");

List<List<String>> nestedList = Arrays.asList(fun1, fun2);
nestedList.stream().map(x -> {
    return x.stream().map(a -> a.toUpperCase());
}).forEach(x ->x.forEach(a->output(a)));

控制台输出:

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
INFO-> ONE
INFO-> TWO
INFO-> THREE
INFO-> FOUR
INFO-> FIVE
INFO-> SIX

Process finished with exit code 0

flatMap 方法

让我们在上述代码中将map()更改为flatMap(),然后查看输出。

  • 先来一个简单

演示 Demo:

List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");
List<List<String>> nestedList = Arrays.asList(fun1, fun2);
nestedList.stream().flatMap(x -> x.stream()).map(x->x.toUpperCase()).forEach(x -> output(x));

控制台输出:

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
INFO-> ONE
INFO-> TWO
INFO-> THREE
INFO-> FOUR
INFO-> FIVE
INFO-> SIX

Process finished with exit code 0

相当于在.flatMap(x -> x.stream())这个时候我们把x.stream()返回的stream对象合并成了一个新的stream对象。这一点在Stream类的方法注释中找到了印证。

    /**
    ·····
 * @return the new stream
 */
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

Java 8 map() 与 flatMap()

map()flatMap()方法都可以应用于Stream<T>Optional<T>对象。并且都返回Stream<R>Optional <U>对象。区别在于map()操作为每个输入值生成一个输出值,而flatMap()操作为每个输入值生成任意数量(零个或多个)的输出值。

flatMap()中,每个输入始终是一个集合,可以是ListSetMap

map()操作采用一个方法,该方法针对输入流中的每个值调用,并生成一个结果值,该结果值返回至stream

flatMap()操作采用的功能在概念上消耗一个集合对象并产生任意数量的值。但是在 Java 中方法返回任意数目的值很麻烦,因为方法只能返回void或一个对象。

演示 Demo:

List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");
Stream.of(fun1,fun2).flatMap(List::stream).forEach(Output::output);

控制台输出:

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
INFO-> one
INFO-> two
INFO-> three
INFO-> four
INFO-> five
INFO-> six

Process finished with exit code 0


公众号FunTester首发,原创分享爱好者,腾讯云和掘金社区首页推荐,知乎七级原创作者,欢迎关注、交流,禁止第三方擅自转载。

FunTester 热文精选

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册