Stream1.クラスのメソッド一覧

このクラスは、データ ストリームのチェーンを簡単に構築Streamできるようにするために作成されました。これを実現するために、クラスには新しいオブジェクトを返すメソッドが用意されています。Stream<T>Stream

これらのデータ ストリームはそれぞれ 1 つの単純なアクションを実行しますが、それらをチェーンに結合し、興味深いラムダ関数を追加すると、必要な出力を生成するための強力なメカニズムが得られます。すぐにあなた自身の目でわかるでしょう。

このクラスのメソッドは次のとおりですStream(最も基本的なもののみ)。

メソッド 説明
Stream<T> of()
オブジェクトのセットからストリームを作成します
Stream<T> generate()
指定されたルールに従ってストリームを生成します
Stream<T> concat()
2 つのストリームを連結します
Stream<T> filter()
データをフィルタリングし、指定されたルールに一致するデータのみを渡します
Stream<T> distinct()
重複を削除します。すでに検出されたデータは引き継がれません
Stream<T> sorted()
データを並べ替えます
Stream<T> peek()
ストリーム内の各要素に対してアクションを実行します。
Stream<T> limit(n)
指定された制限を超えないように切り詰められたストリームを返します。
Stream<T> skip(n)
最初の n 要素をスキップします
Stream<R> map()
データをあるタイプから別のタイプに変換します
Stream<R> flatMap()
データをあるタイプから別のタイプに変換します
boolean anyMatch()
指定されたルールに一致する要素がストリーム内に少なくとも 1 つあるかどうかを確認します
boolean allMatch()
ストリーム内のすべての要素が指定されたルールに一致するかどうかを確認します
boolean noneMatch()
ストリーム内のどの要素も指定されたルールに一致しないかどうかをチェックします
Optional<T> findFirst()
ルールに一致する最初の要素を返します。
Optional<T> findAny()
ルールに一致するストリーム内の要素を返します。
Optional<T> min()
データストリーム内の最小要素を検索します。
Optional<T> max()
データストリーム内の最大要素を返します。
long count()
データストリーム内の要素の数を返します。
R collect()
ストリームからすべてのデータを読み取り、コレクションとして返します。

Stream2.クラスによる中間および末端の操作

ご覧のとおり、上の表のすべてのメソッドが を返すわけではありませんStream。これは、クラスのメソッドが中間(非端末とも呼ばれる) メソッドと端末メソッドStreamに分割できるという事実に関連しています。

中間メソッド

中間メソッドはインターフェイスを実装するオブジェクトを返しStream、それらを連結することができます。

ターミナルメソッド

ターミナルメソッドは 以外の値を返しますStream

メソッド呼び出しパイプライン

したがって、任意の数の中間メソッドと最後に 1 つのターミナル メソッド呼び出しで構成されるストリーム パイプラインを構築できます。このアプローチにより、コードの可読性を高めながら、かなり複雑なロジックを実装できます。

メソッド呼び出しパイプライン

データ ストリーム内のデータはまったく変更されません。中間メソッドのチェーンは、ターミナル メソッドの呼び出し後に実行されるデータ処理パイプラインを指定する洗練された (宣言的) 方法です。

つまり、ターミナル メソッドが呼び出されない場合、データ ストリーム内のデータはまったく処理されません。ターミナル メソッドが呼び出された後でのみ、ストリーム パイプラインで指定されたルールに従ってデータの処理が開始されます。

stream()
  .intemediateOperation1()
  .intemediateOperation2()
  ...
  .intemediateOperationN()
  .terminalOperation();
パイプラインの一般的な外観

中間メソッドと末端メソッドの比較:

中級 ターミナル
戻り値の型 Stream ではないStream
同じタイプの複数のメソッドと組み合わせてパイプラインを形成できます はい いいえ
単一パイプライン内のメソッドの数 どれでも 一つしかない
最終結果を生み出す いいえ はい
ストリーム内のデータの処理を開始します いいえ はい

例を見てみましょう。

動物愛好家のためのクラブがあるとします。明日、クラブはジンジャーキャットデーを祝います。クラブにはペットの飼い主がおり、それぞれがペットのリストを持っています。彼らは猫に限定されません。

タスク:明日の「プロフェッショナル ホリデー」に向けて、ジンジャー キャット用のパーソナライズされたグリーティング カードを作成するには、すべてのジンジャー キャットの名前をすべて特定する必要があります。グリーティングカードは、猫の年齢に応じて、最年長から最年少まで並べ替える必要があります。

まず、このタスクの解決に役立ついくつかのクラスを提供します。

public enum Color {
   WHITE,
   BLACK,
   DARK_GREY,
   LIGHT_GREY,
   FOXY,
   GREEN,
   YELLOW,
   BLUE,
   MAGENTA
}
public abstract class Animal {
   private String name;
   private Color color;
   private int age;

   public Animal(String name, Color color, int age) {
      this.name = name;
      this.color = color;
      this.age = age;
   }

   public String getName() {
      return name;
   }

   public Color getColor() {
      return color;
   }

   public int getAge() {
      return age;
   }
}
public class Cat extends Animal {
   public Cat(String name, Color color, int age) {
      super(name, color, age);
   }
}
public class Dog extends Animal {
   public Dog(String name, Color color, int age) {
      super(name, color, age);
   }
}
public class Parrot extends Animal {
   public Parrot(String name, Color color, int age) {
      super(name, color, age);
   }
}
public class Pig extends Animal {
   public Pig(String name, Color color, int age) {
      super(name, color, age);
   }
}
public class Snake extends Animal {
   public Snake(String name, Color color, int age) {
      super(name, color, age);
   }
}
public class Owner {
   private String name;
   private List<Animal> pets = new ArrayList<>();

   public Owner(String name) {
      this.name = name;
   }

   public List<Animal> getPets() {
      return pets;
   }
}

Selector次に、指定された基準に従って選択が行われるクラスを見てみましょう。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Selector {
   private static List<Owner> owners;

   private static void initData() {
      final Owner owner1 = new Owner("Ronan Turner");
      owner1.getPets().addAll(List.of(
            new Cat("Baron", Color.BLACK, 3),
            new Cat("Sultan", Color.DARK_GREY, 4),
            new Dog("Elsa", Color.WHITE, 0)
      ));

      final Owner owner2 = new Owner("Scarlet Murray");
      owner2.getPets().addAll(List.of(
            new Cat("Ginger", Color.FOXY, 7),
            new Cat("Oscar", Color.FOXY, 5),
            new Parrot("Admiral", Color.BLUE, 3)
      ));

      final Owner owner3 = new Owner("Felicity Mason");
      owner3.getPets().addAll(List.of(
            new Dog("Arnold", Color.FOXY, 3),
            new Pig("Vacuum Cleaner", Color.LIGHT_GREY, 8)
      ));

      final Owner owner4 = new Owner("Mitchell Stone");
      owner4.getPets().addAll(List.of(
            new Snake("Mr. Boa", Color.DARK_GREY, 2)
      ));

      final Owner owner5 = new Owner("Jonathan Snyder");
      owner5.getPets().addAll(List.of(
            new Cat("Fisher", Color.BLACK, 16),
            new Cat("Zorro", Color.FOXY, 14),
            new Cat("Margo", Color.WHITE, 3),
            new Cat("Brawler", Color.DARK_GREY, 1)
      ));

      owners = List.of(owner1, owner2, owner3, owner4, owner5);
   }
}

残っているのは、メソッドにコードを追加することですmain。現在、最初にinitData()メソッドを呼び出して、クラブ内のペットの所有者のリストを設定します。次に、生姜猫の名前を年齢順に降順に選択します。

まず、このタスクを解決するためにストリームを使用しないコードを見てみましょう。

public static void main(String[] args) {
   initData();

   List<String> findNames = new ArrayList<>();
   List<Cat> findCats = new ArrayList<>();
   for (Owner owner : owners) {
      for (Animal pet : owner.getPets()) {
         if (Cat.class.equals(pet.getClass()) && Color.FOXY == pet.getColor()) {
            findCats.add((Cat) pet);
         }
      }
   }

   Collections.sort(findCats, new Comparator<Cat>() {
      public int compare(Cat o1, Cat o2) {
         return o2.getAge() - o1.getAge();
      }
   });

   for (Cat cat : findCats) {
      findNames.add(cat.getName());
   }

   findNames.forEach(System.out::println);
}

次に、代替案を見てみましょう。

public static void main(String[] args) {
   initData();

   final List<String> findNames = owners.stream()
           .flatMap(owner -> owner.getPets().stream())
           .filter(pet -> Cat.class.equals(pet.getClass()))
           .filter(cat -> Color.FOXY == cat.getColor())
           .sorted((o1, o2) -> o2.getAge() - o1.getAge())
           .map(Animal::getName)
           .collect(Collectors.toList());

   findNames.forEach(System.out::println);
}

ご覧のとおり、コードははるかにコンパクトになっています。さらに、ストリーム パイプラインの各行は 1 つのアクションであるため、英語の文章のように読むことができます。

.flatMap(owner -> owner.getPets().stream())
a からStream<Owner>a に移動するStream<Pet>
.filter(pet -> Cat.class.equals(pet.getClass()))
データ ストリームに猫だけを保持する
.filter(cat -> Color.FOXY == cat.getColor())
データストリーム内にジンジャーキャットのみを保持する
.sorted((o1, o2) -> o2.getAge() - o1.getAge())
年齢順に並べ替えます
.map(Animal::getName)
名前を取得する
.collect(Collectors.toList())
結果をリストにまとめる

3. ストリームの作成

このStreamクラスには、まだ説明していない 3 つのメソッドがあります。これら 3 つのメソッドの目的は、新しいスレッドを作成することです。

Stream<T>.of(T obj)方法

このof()メソッドは、単一の要素で構成されるストリームを作成します。これは通常、関数がStream<T>引数としてオブジェクトを取るが、オブジェクトしかない場合に必要になりますTその後、このメソッドを使用して、単一の要素で構成されるストリームを簡単にof()取得できます。

例:

Stream<Integer> stream = Stream.of(1);

Stream<T> Stream.of(T obj1, T obj2, T obj3, ...)方法

このof()メソッドは、渡された要素で構成されるストリームを作成します。要素はいくつでも許可されます。例:

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);

Stream<T> Stream.generate(Supplier<T> obj)方法

このgenerate()メソッドを使用すると、ストリームが要求されたときにストリームの次の要素を生成するために使用されるルールを設定できます。たとえば、毎回乱数を与えることができます。

例:

Stream<Double> s = Stream.generate(Math::random);

Stream<T> Stream.concat(Stream<T> a, Stream<T> b)方法

このconcat()メソッドは、渡された 2 つのストリームを1 つに連結します。データが読み取られるときは、まず最初のストリームから読み取られ、次に 2 番目のストリームから読み取られます。例:

Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream2 = Stream.of(10, 11, 12, 13, 14);
Stream<Integer> result = Stream.concat(stream1, stream2);

4. データのフィルタリング

別の 6 つのメソッドは新しいデータ ストリームを作成し、ストリームをさまざまな複雑さのチェーン (またはパイプライン) に結合できます。

Stream<T> filter(Predicate<T>)方法

このメソッドは、渡されたルールに従ってソース データ ストリームをフィルタリングする新しいデータ ストリームを返します。このメソッドは、タイプが のオブジェクトに対して呼び出される必要があります。Stream<T>

ラムダ関数を使用してフィルタリング ルールを指定できます。ラムダ関数はコンパイラによってオブジェクトに変換されますPredicate<T>

例:

連鎖ストリーム 説明
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream2 = stream.filter(x -> (x < 3));

3 未満の数値のみを保持する
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
Stream<Integer> stream2 = stream.filter(x -> (x > 0));

ゼロより大きい数値のみを保持する

Stream<T> sorted(Comparator<T>)方法

このメソッドは、ソース ストリーム内のデータを並べ替える新しいデータ ストリームを返します。データ ストリームの 2 つの要素を比較するためのルールを設定するcomparatorを渡します。

Stream<T> distinct()方法

このメソッドは、ソース データ ストリーム内の固有の要素のみを含む新しいデータ ストリームを返します。重複したデータはすべて破棄されます。例:

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.distinct(); // 1, 2, 3, 4, 5

Stream<T> peek(Consumer<T>)方法

このメソッドは新しいデータ ストリームを返しますが、そのデータはソース ストリームと同じです。ただし、ストリームから次の要素が要求されると、メソッドに渡した関数がpeek()一緒に呼び出されます。

System.out::println関数をメソッドに渡すとpeek()、ストリームを通過するときにすべてのオブジェクトが表示されます。

Stream<T> limit(int n)方法

このメソッドは、ソース データ ストリーム最初の要素のみを含む新しいデータ ストリームを返します。他のすべてのデータは破棄されます。例:n

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.limit(3); // 1, 2, 3

Stream<T> skip(int n)方法

このメソッドは、ソース ストリームと同じ要素をすべて含む新しいデータ ストリームを返しますが、最初の要素はスキップ(無視) されます。例:n

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.skip(3); // 4, 5, 2, 2, 2, 3, 4