Java 中的 flatMap

Mohammad Irfan 2023年1月30日 2022年4月26日
  1. Java 中的 flatMap 函数
  2. 在 Java 中如何使用 flatMap() 方法
  3. 从 Java 中的 flatMap 中删除重复项
  4. 在 Java 中过滤 flatMap 元素
  5. flatMap 和原始类型
  6. 结论
Java 中的 flatMap

本教程介绍 flatMap 以及如何在 Java 中使用它。

flatMap 是 Java 流中的一个操作/函数,用于在执行某些功能性任务后获取新流。在这里,我们将讨论 flatMap() 操作。

此操作是 map() 操作的扩展。此函数应用于每个流元素并生成新值流。

然后将这些新流的生成元素复制到最近创建的流中,该流用作方法的返回值。

Java 中的 flatMap 函数

flatMap() 函数的签名是:

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

flatMap 是一个中间操作。中间操作是惰性操作,在 Stream 实例上调用,在它们完成处理后,它们返回一个 Stream 实例。

flatMap() 操作是 map()flat() 操作的组合。这意味着 flatMap() 操作首先应用 map() 操作,然后将结果展平。

此方法采用映射器,该函数将应用于传入的 Stream 的每个元素。

Java 中的扁平化

我们先来了解一下什么是扁平化。展平列表会将两个或多个级别列表转换为单个级别列表。

两个 2 级列表的示例是:

[["I"], ["Love"], ["Delft", "Stack"]]

扁平化后的上述列表转换为:

["I", "Love", "Delft", "Stack"]

生成的列表是单级列表。

扁平化列表的必要性

有必要对一个列表进行扁平化处理,因为处理几个 Stream 级别是很困难、很复杂、很容易出错的。

我们可以使用 Stream.flatMap() 操作将两个 Stream 级别转换为单个级别 Stream。我们将在本文后面使用一个示例来理解这一点。

在 Java 中如何使用 flatMap() 方法

在这个例子中,我们首先使用 stream() 方法从 List 创建了一个对象流。每个对象都是公司的程序员。

我们将首先创建一个类来代表公司中的开发人员/程序员。

import java.util.HashSet;
import java.util.Set;
class Programmer{
    private String name;
    private Set<String> languages_known;

    public Programmer(String name){
        this.name = name;
        this.languages_known = new HashSet<>();
    }

    public void addLanguage(String lang){
        this.languages_known.add(lang);
    }

    public Set<String> getLanguages(){
        return languages_known;
    }
}

我们现在将初始化对象并创建一个列表列表,其中包含整个公司程序员已知的所有语言。然后,我们将扁平化该列表以了解团队中的所有语言。

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class SimpleTesting{
    public static void main(String[] args) {
        Programmer raj = new Programmer("Raj");
        raj.addLanguage("Java");
        raj.addLanguage("Dart");
        raj.addLanguage("go");
        raj.addLanguage("groovy");
        
        Programmer karan = new Programmer("Karan");
        karan.addLanguage("Java");
        karan.addLanguage("Python");

        Programmer chahal = new Programmer("Chahal");
        chahal.addLanguage("Dart");
        chahal.addLanguage("Javascript");

        List<Programmer> team = new ArrayList<>();
        team.add(raj);
        team.add(karan);
        team.add(chahal);

        System.out.println("Programming languages in the team: ");
        List<String> languages = team.stream().map(Programmer::getLanguages).flatMap(Collection::stream).collect(Collectors.toList());
        System.out.println(languages);
    }
}

输出:

Programming languages in the team: 
[Java, groovy, go, Dart, Java, Python, Javascript, Dart]

在上面的示例中,我们首先使用流 API 创建了所有程序员的流。之后,我们使用 map() 函数创建了每个程序员都知道的语言列表流。

从 Java 中的 flatMap 中删除重复项

然后我们使用 flatMap() 操作展平这个列表,并将结果流转换为一个列表。请注意,生成的 List 有一些重复值;我们使用 duplicate() 操作来消除这些。

看看下面的代码。

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class SimpleTesting{
    public static void main(String[] args) {
        Programmer raj = new Programmer("Raj");
        raj.addLanguage("Java");
        raj.addLanguage("Dart");
        raj.addLanguage("go");
        raj.addLanguage("groovy");
        Programmer karan = new Programmer("Karan");
        karan.addLanguage("Java");
        karan.addLanguage("Python");
        Programmer chahal = new Programmer("Chahal");
        chahal.addLanguage("Dart");
        chahal.addLanguage("Javascript");
        List<Programmer> team = new ArrayList<>();
        team.add(raj);
        team.add(karan);
        team.add(chahal);
        System.out.println("Programming languages in the team: ");
        List<String> languages = team.stream()
                                    .map(Programmer::getLanguages)
                                    .flatMap(Collection::stream)
                                    .distinct()
                                    .collect(Collectors.toList());
        System.out.println(languages);
    }
}

输出:

Programming languages in the team: 
[Java, groovy, go, Dart, Python, Javascript]

在 Java 中过滤 flatMap 元素

如果我们想要获取除 Dart 之外的所有语言,我们可以使用 filter() 函数和 flatMap()。看看下面的代码。

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class SimpleTesting{
    public static void main(String[] args) {
        Programmer raj = new Programmer("Raj");
        raj.addLanguage("Java");
        raj.addLanguage("Dart");
        raj.addLanguage("go");
        raj.addLanguage("groovy");
        Programmer karan = new Programmer("Karan");
        karan.addLanguage("Java");
        karan.addLanguage("Python");
        Programmer chahal = new Programmer("Chahal");
        chahal.addLanguage("Dart");
        chahal.addLanguage("Javascript");
        List<Programmer> team = new ArrayList<>();
        team.add(raj);
        team.add(karan);
        team.add(chahal);
        System.out.println("Programming languages in the team: ");
        List<String> languages = team.stream()
                                    .map(Programmer::getLanguages)
                                    .flatMap(Collection::stream)
                                    .distinct()
                                    .filter(x -> !x.equals("Dart"))
                                    .collect(Collectors.toList());
        System.out.println(languages);
    }
}

输出:

Programming languages in the team:
[Java, groovy, go, Python, Javascript]

flatMap 和原始类型

Java Stream API 还为原始数据类型(如 int、float、long)提供了单独的操作,如 flatMapto{primitive type} 以扁平化原始类型的 Stream。

import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class SimpleTesting{
    public static void main(String[] args) {
        int[] Je_array= {3,5,2,35,85,32,23,43,12};
        Stream<int[]> JE_streamArray = Stream.of(Je_array);
        IntStream JE_intStream = JE_streamArray.flatMapToInt(x -> Arrays.stream(x));
        JE_intStream.forEach(x -> System.out.println(x));
    }
}

输出:

3
5
2
35
85
32
23
43
12

结论

我们已经讨论了 flatMap() 操作以及为什么需要它。我们还讨论了 Java Stream API 如何为原始数据类型提供单独的 flatMap() 操作。

请注意,普通的 flatMap() 操作也适用于原始数据类型。

相关文章 - Java Stream