为啥 flatMap 不将 Stream<Stream<SomeClass>> 扁平化到 SomeClass 而是扁平化到 Stream<SomeClass>?

Posted

技术标签:

【中文标题】为啥 flatMap 不将 Stream<Stream<SomeClass>> 扁平化到 SomeClass 而是扁平化到 Stream<SomeClass>?【英文标题】:Why flatMap doesn't flat Stream<Stream<SomeClass>> to the SomeClass but rather to Stream<SomeClass>?为什么 flatMap 不将 Stream<Stream<SomeClass>> 扁平化到 SomeClass 而是扁平化到 Stream<SomeClass>? 【发布时间】:2021-10-01 11:14:34 【问题描述】:

我读到的关于 flatMap 的内容:

要了解扁平化流的含义,请考虑一个 像 [ [1,2,3],[4,5,6],[7,8,9] ] 这样的结构,它有“两个层次”。 展平这意味着将其转换为“一层”结构:[ 1,2,3,4,5,6,7,8,9]

import java.util.List;
import java.util.stream.Stream;

public class FlatMapDemo 
    List<Country> countries;
    void demoFlatMap()
        Stream<Stream<City>> streamStreamCity = countries
                .stream()
                .map(country -> country.cities.stream());
        streamStreamCity.flatMap(cityStream -> /*it's not City, it's Stream<City> !!!*/);
    

class Country
    List<City> cities;

class City 
    int population;

所以我只想计算来自所有国家的所有人口,但城市人口超过 1000 人。所以我创建了Stream&lt;Stream&lt;City&gt;&gt; 并希望flatMap flat 为我Stream&lt;Stream 并给我City 类采取类似:.flatMap(city -&gt; city.population) 过滤后:.filter(population &gt; 1000) 但似乎我错了。请解释为什么 flatMap 不这样做?不就是扁平化的目的吗?

【问题讨论】:

不需要将flatMap拆分为单独的操作,可以在map()方法之后继续拆分。您将其从 Stream 扁平化为 Stream,因此现在您可以添加过滤器,如 filter(county.getPopulation() > 1000) 和一个谓词,该谓词将过滤具有 > 1000 居民的城市,然后使用终端操作收集(Collectors.counting());最后将返回与上述谓词匹配的记录数。 我拆分它只是为了暴露变量的类型:Stream&lt;Stream&lt;City&gt;&gt;,我的问题是:为什么flatMap 没有从Stream&lt;Stream&lt;City&gt;&gt; 到达City 所以:int sum = streamStreamCity.flatMap(cityStream -&gt; cityStream) .filter(city -&gt; city.population &gt; 1000) .mapToInt(city -&gt; city.population) .sum(); - 对吧? flatMap 操作将流的流扁平化为单个流。如果我正确理解你想要什么,你应该做int totalPopulation = countries.stream().flatMap(country -&gt; country.cities.stream()).mapToInt(city -&gt; city.population).filter(population -&gt; population &gt; 1000).sum() 这能回答你的问题吗? What's the difference between map() and flatMap() methods in Java 8? 【参考方案1】:

flatMap() 的目标不是对 Stream&lt;Stream&lt;A&gt;&gt;A 项应用转换。如果您最终得到这样的类型,则很可能表明您在某处误用了 map() 操作。

flatMap() 的目标是将Stream&lt;A&gt; 转换为Stream&lt;B&gt;,当您有一个函数f 可以从单个A 元素生成Stream&lt;B&gt;(简化一点,它是Function&lt;A, Stream&lt;B&gt;&gt;)。 IE。它通过避免以嵌套流结束来“扁平化”流。

你会像这样使用它

getStreamOfA().flatMap(f) // returns Stream<B>

所以在你的例子中:

Stream<City> cityStream = countries
                .stream()
                .flatMap(country -> country.cities.stream());

【讨论】:

以上是关于为啥 flatMap 不将 Stream<Stream<SomeClass>> 扁平化到 SomeClass 而是扁平化到 Stream<SomeClass>?的主要内容,如果未能解决你的问题,请参考以下文章

Java8Stream的flatmap方法使用

为什么在flatMap之后收集更改流处理顺序? [重复]

flatMap

java8 stream流操作的flatMap(流的扁平化)

删除父对象时如何删除由stream.flatMap创建的列表中的子对象?

为啥 IIS 中的 Windows/集成身份验证不将用户凭据传递给 s-s-rS 和 SQL?