0%

stream and lambda(9) - 中间操作之map操作(map、flatmap)

map 操作算是比较常用的操作了,它可以将元素经过处理后输出成另一个元素。这就和 java method 很像了,输入参数,经过方法处理,输出一个返回参数。

map

方法定义

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

map 方法看起来就很简洁明了,入参是 Function,作用是将元素 T 经过逻辑处理后转换成 R。当然,这个转换过程中可做的东西就多了。比如类型转换、属性提取、逻辑运算、业务处理等。

stream map 转换

使用举例

1
2
3
4
5
public void mapTest() {
Stream<Integer> of = Stream.of(1, 23, 4);
List<String> result = of.map(i -> "my value is " + i).collect(Collectors.toList());
System.out.println(result);
}

运行后输出如下:

[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 对象转换成流。

大致过程如下图,这样看你就明白是怎么 压平 了的了。

stream flatmap 转换

使用举例

首先,我们还是看下 map,然后再看 flatmap,这样才更容易对比理解。

先给定初始字符串数组:

1
String[] strs = {"this", "is", "flatmap"};
  1. 将三个字符串后加上空格依次打印
1
Arrays.stream(strs).map(str -> str + " ").forEach(System.out::print);

此时,对于三个元素,是转换成了另一个字符串

  1. 将所有字母依次输出

一般思路是将这三个字符串分割成单个字母进行输出,我们尝试一下下面的代码

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