先看一段代码:
val strings = listOf("abc", "de")
strings.map { s -> s.toList() }
strings.flatMap { s -> s.toSet() }.run { println("flatMap: $this") }
// flatMap: [a, b, c, d, e]
strings.map { s -> s.toSet() }.run { println("map: $this") }
// map: [[a, b, c], [d, e]]
strings.map { s -> s.toSet() }.flatten().run { println("map + flatten : $this") }
看输出:
flatMap: [a, b, c, d, e]
map: [[a, b, c], [d, e]]
map + flatten : [a, b, c, d, e]
看源码:
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>
.mapTo(destination: C, transform: (T) -> R): C {
for (item in this)
destination.add(transform(item))
return destination
}
// =================
public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
return flatMapTo(ArrayList<R>(), transform)
}
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>
.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
for (element in this) {
val list = transform(element)
destination.addAll(list)
}
return destination
}
对比 map 与 flatMap 发现区别在于一个是调用 add() , 一个是调用 addAll().
这就明白了,为什么上面的输出 flatMap 之后是一个集合,每个元素是原始数据;而 map 之后,每个元素是一个集合。
其实 kt 的 map 与 flatMap 是对集合的操作,而 rxJava2 中是对 Flowable 进行操作的。
也就是二者其实并没有什么对比性。但是由于函数名相同容易让人混淆。
看一下 rxJava 的 map 与 FlatMap 源码
public final <R> Flowable<R> map(Function<? super T, ? extends R> mapper) {
ObjectHelper.requireNonNull(mapper, "mapper is null");
return RxJavaPlugins.onAssembly(new FlowableMap<T, R>(this, mapper));
}
public final <R> Flowable<R> flatMap(Function<? super T, ? extends Publisher<? extends R>> mapper,
boolean delayErrors, int maxConcurrency, int bufferSize) {
ObjectHelper.requireNonNull(mapper, "mapper is null");
ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency");
ObjectHelper.verifyPositive(bufferSize, "bufferSize");
if (this instanceof ScalarCallable) {
@SuppressWarnings("unchecked")
T v = ((ScalarCallable<T>)this).call();
if (v == null) {
return empty();
}
return FlowableScalarXMap.scalarXMap(v, mapper);
}
return RxJavaPlugins.onAssembly(new FlowableFlatMap<T, R>(this, mapper, delayErrors, maxConcurrency, bufferSize));
}
主要看Function
的第二个参数的类型,对于 map 操作,第二个参数类型是? extends R
;而 flatMap 的第二个参数的类型是? extends Publisher<? extends R>>
。
Flowable 是 Publisher 接口的一个实现类
看到参数的区别也就明白了,rxJava 通过 map 操作,可以改变 Floawable 中数据的类型,而 flatMap 是根据 原有数据转成一个新的 Flowable
类型了。一般来讲,flatMap 是根据之前的 Flowable 里面的数据进行二次转换。
算了,不继续解释 rxJava 中的 flatMap 了,想了解的去看其他文章吧。
结论强调:kt 的 flatMap 是对集合的操作,是一个平铺操作;rxJava 的 flatMap 是将 数据转成 一个新的 数据源。二者没有共通的地方。(概念上是共通的,实际用法没有共通的地方)