先看一段代码:


    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 是将 数据转成 一个新的 数据源。二者没有共通的地方。(概念上是共通的,实际用法没有共通的地方)


版权声明:本文为DucklikeJAVA原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/DucklikeJAVA/article/details/101129131