最近看到一篇讲stream
语法的文章,学习Java
中map()
和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()
中,每个输入始终是一个集合,可以是List
或Set
或Map
。
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首发,原创分享爱好者,腾讯云和掘金社区首页推荐,知乎七级原创作者,欢迎关注、交流,禁止第三方擅自转载。