map 操作算是比较常用的操作了,它可以将元素经过处理后输出成另一个元素。这就和 java method
很像了,输入参数,经过方法处理,输出一个返回参数。
map
方法定义
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
map
方法看起来就很简洁明了,入参是 Function
,作用是将元素 T 经过逻辑处理后转换成 R。当然,这个转换过程中可做的东西就多了。比如类型转换、属性提取、逻辑运算、业务处理等。
使用举例
1 | public void mapTest() { |
运行后输出如下:
[my value is 1, my value is 23, my value is 4]
经过 map,我们将一个数字转成了一大串的字符串。(小声BB,这要是能把我的余额 map(money -> 100 * money)
该有多好啊)
flatmap
方法定义
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
flatmap
就很容易让人分不清和 map
的区别了。
首先先从名字上看,压平了 map
?往死里给我 map
?
还是从入参上来分析吧。经过 Function
运算,把元素转化成一个 Stream
。了解了,和 map
的区别是,map
是把元素从 A 对象转换成 B 对象,而 flatmap
是把元素从 A 对象转换成流。
大致过程如下图,这样看你就明白是怎么 压平
了的了。
使用举例
首先,我们还是看下 map
,然后再看 flatmap
,这样才更容易对比理解。
先给定初始字符串数组:
1 | String[] strs = {"this", "is", "flatmap"}; |
- 将三个字符串后加上空格依次打印
1 | Arrays.stream(strs).map(str -> str + " ").forEach(System.out::print); |
此时,对于三个元素,是转换成了另一个字符串
- 将所有字母依次输出
一般思路是将这三个字符串分割成单个字母进行输出,我们尝试一下下面的代码
1 | Arrays.stream(strs).map(str -> str.split("")).forEach(System.out::print); |
此时,我们预期的是输出 thisisflatmap
,但是实际上输出的却是 [Ljava.lang.String;@36b4cef0[Ljava.lang.String;@fad74ee[Ljava.lang.String;@1a1d6a08
。看来,输出的并不是单个的字母,为什么呢?
原因就在于,map
之后,字符串转成了数组,所以输出了数组。想要输出单个字符怎么办?把数组压平(flat),把数组里的元素压出来。
1 | Arrays.stream(strs).map(str -> str.split("")).flatMap(Arrays::stream).forEach(System.out::print); |
此时,输出的就是 thisisflatmap
了。
当然,了解了 flatmap
,也可以这样写。
1 | Arrays.stream(strs).flatMap(str -> Arrays.stream(str.split(""))).forEach(System.out::print); |
总结
map
的本质就是传入一个Function
,将单个元素转成另一个元素,然后将所有元素组成一个新的Stream
。flatmap
的本质是传入一个Function
,将单个元素转成一个Stream
,然后将多个Stream
合并成一个新的Stream
。- 如果还是有些迷糊,请看图。
注:本文配套代码可在
github
查看:stream-and-lambda