Java 中的 flatMap

Mohammad Irfan 2023年10月12日
  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