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つ以上のレベルリストが 1つのレベルリストに変換されます。

2つの 2 レベルのリストの例は次のとおりです。

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

平坦化後の上記のリストは、次のように変換されます。

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

作成されるリストは単一レベルのリストです。

リストを平坦化する必要性

複数のストリームレベルを処理することは困難で、複雑で、エラーが発生しやすいため、リストをフラット化する必要があります。

Stream.flatMap() 操作を使用して、2つのストリームレベルを 1つのレベルのストリームに変換できます。これは、この記事の後半の例を使用して理解します。

Java で flatMap() メソッドを使用する方法

この例では、最初に stream() メソッドを使用してリストからオブジェクトのストリームを作成しました。各オブジェクトは会社のプログラマーです。

まず、会社の開発者/プログラマーを表すクラスを作成します。

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() 操作を使用してこのリストをフラット化し、結果のストリームをリストに変換します。生成されたリストに重複する値があることに注意してください。これらを排除するために、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 を除くすべての言語を取得したい場合は、flatMap()filter() 関数を使用できます。以下のコードを見てください。

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} のような個別の操作も提供します。

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