结论
先说结论:
相同点:
- Map和FlatMap都是流中 集合数据类型的 转换操作符。
不同点:
- Map 是 将 集合数据中每一个元素作为 参数 传入的lambda表达后进行转换操作, 得到的结果用一个ArrayList 收集起来。
- FlatMap, 一个Flat(扁平化),一个Map,顾名思义, 就是在Map的基础上,会将集合的数据结构给展开。
- FlatMap传入的lambda表达式的返回值必须为集合接口类型。
举个很简单的例子:
Map 操作
// 如果我们把List中的 所有字符变为大写。那么:
[['a', 'b', 'c'], ['d', 'e', 'f']] =>> [['A', 'B', 'C'], ['D', 'E', 'F']]
FlatMap 操作
[['a', 'b', 'c'], ['d', 'e', 'f']] =>> ['A', 'B', 'C', 'D', 'E', 'F']
源码分析
Map
首先,我们看一下map, map是集合接口Iterable的一个扩展函数,它有两个泛型 T和R, T是集合接口容器包裹的元素数据类型,以上面的例子就是List<Char>, R 是lambda表达式的返回类型,也是map操作后所得到的集合容器装载元素的数据类型,以上面的例子<List<Char>>。
transform是一个lambda表达式,或说函数类型,它的参数类型是T,返回值类型是R,当我们调用了map操作符后,它干了什么呢?
它就是直接 将一个 新的ArrayList和lambda表达式一并传入mapTo()方法中。
那么它在mapTo方法中做了什么呢?
非常简单,就是遍历一遍 集合, 以上面的例子 遍历的结果就是 [‘a’, ‘b’, ‘c’] 和 [‘d’, ‘e’, ‘f’]两个元素,
将这些元素分别执行lambda表达式,将得到的结果用那个 新的ArrayList收集起来。
flatMap
然后我们看看flatMap的源码:
flatMap也是一样的,是集合接口Iterable的一个扩展函数,操作符需要传入一个lambda表达式,不同的是这个lambda表达式的返回值是一个 集合接口类型(list, set等)。它创建了一个新的ArrayList实例,把实例和lambda表达式一并作为参数传入 flatMapTo方法中。
我们看看flatMapTo干了啥?flatMap先是遍历一遍集合内的元素,将每一个元素按照lambda表达式的逻辑进行处理, 处理后的结果(集合接口类型)将它添加到 新的ArrayList, 注意了,它添加的方式是 addAll(集合接口)。
这个方法就自然而然把元素的集合结构给展开了。
问题
那我要是这种3层数据结构呢?,怎么把它们展开转化为大写字母?
[ [ ['a', 'b'], ['c', 'd'] ], [ ['e', 'f'], ['g', 'h'] ] ] ==>
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
很简单,先flatMap展开两层,然后map就好了。
val orgList: List<List<List<Char>>> = listOf(
listOf(
listOf('a', 'b'),
listOf('c', 'd')
),
listOf(
listOf('e', 'f'),
listOf('g', 'h')
)
)
val transList = orgList.flatMap { outterList ->
outterList.flatMap { innerList ->
innerList.map { charStr ->
charStr.uppercaseChar()
}
}
}