Java 8無限ストリーム生成(Infinite Streams)

3302 ワード

Java 8無限ストリーム生成(Infinite Streams)
本文はjavaを勉強します.util.Stream APIでは、この構造を使用して無限のデータ/要素ストリームを操作する方法が表示されます.無限要素シーケンスを処理する可能性は,ストリームが不活性に構築されるという事実に基づいている.この不活性化は、ストリーム上で実行される2つのタイプの動作(中間動作および終了動作)を分離することによって達成される.
1.中間操作と終了操作
すべてのフロー操作は、中間操作と終了操作の2種類に分けられ、パイプフロー形式に組み合わせられる.パイプフローは、ソース(コレクション、配列、ジェネレータ関数、i/o channel、無限シーケンスジェネレータなど)によって、ゼロまたは複数の中間操作と1つの終了操作に続く.
1.1. 中間操作
中間操作は、操作の実行が終了した場合にのみ実行されます.これらは、パイプフローとして生中継され、次の方法でパイプフローに追加できます.
  • filter()
  • map()
  • flatMap()
  • distinct()
  • sorted()
  • peek()
  • limit()
  • skip()

  • すべての中間操作は、実際に結果を処理する必要があるまで実行されません.中間操作を実行すると、実際には何も実行されず、新しいストリームが作成されます.ストリームを遍歴すると、所与の述語に一致する元のストリームの要素が含まれます.したがって、パイプの終了操作を実行するまで、フローのループは開始されません.
    これは、呼び出しが終了したときにのみ実際に呼び出されるストリームを作成できるため、無限ストリームにとって特に重要な特性です.
    1.2. 操作の終了
    終了操作は、ストリームを巡って結果を生成したり、直接消費したりすることができます.操作を終了すると,パイプフローが消費され,これ以上使用できないと考えられる.ほとんどの場合、端末操作は直ちに実行され、戻る前にデータソースの遍歴とパイプの処理が完了します.
    動作を終了する即時性は無限ストリームにとって重要な概念であり、処理時にストリームが正しく制限されているかどうかを注意深く考慮する必要があるため、例えばlimit()動作である.終了操作は次のとおりです.
  • forEach()
  • forEachOrdered()
  • toArray()
  • reduce()
  • collect()
  • min()
  • max()
  • count()
  • anyMatch()
  • allMatch()
  • noneMatch()
  • findFirst()
  • findAny()

  • これらの各操作は、すべての中間操作をトリガーします.
    2.無限流
    次に,中間操作と終了操作の2つの概念を理解し,ストリームの怠惰な実行特性を利用して無限ストリームを書くことができる.
    0から2を追加するたびに無限ストリームを作成し、呼び出しが終了する前に制限メソッドを呼び出す必要があります.collect()メソッドを終了する前にlimit()メソッドを使用することが重要です.そうしないと、プログラムは無限に実行されます.
    // given
    Stream infiniteStream = Stream.iterate(0, i -> i + 2);
     
    // when
    List collect = infiniteStream
      .limit(10)
      .collect(Collectors.toList());
     
    // then
    assertEquals(collect, Arrays.asList(0, 2, 4, 6, 8, 10, 12, 14, 16, 18));
    

    iterate()メソッドで無限ストリームを作成し、limit()メソッドを呼び出して数を制限し、collect()終了メソッドを呼び出します.最終list結果には、無限シーケンスを実行する怠惰な最初の10要素が含まれます.
    3.カスタム要素タイプの無限ストリーム
    ランダムなUUIDの無限ストリームを作成します.ストリームAPI呼び出しを実装する最初のプロバイダーメソッド--ランダム値を生成する:
    Supplier randomUUIDSupplier = UUID::randomUUID;
    

    generate()メソッドと生産者メソッドによって無限ストリームを作成できます.
    Stream infiniteStreamOfRandomUUID = Stream.generate(randomUUIDSupplier);
    

    次に、プログラムが完了したときにlimit()メソッドを使用する要素のセットをストリームから取得できます.
    List randomInts = infiniteStreamOfRandomUUID
      .skip(10)
      .limit(10)
      .collect(Collectors.toList());
    

    skipメソッドを使用して、最初の10要素をスキップし、次の10要素を取ります.ここでgenerate()メソッドと生産者メソッドにより、カスタムタイプの無限ストリームを作成します.
    4.Do-Whileフロー方式
    簡単DO...WHILEループコードを見てください:
    int i = 0;
    while (i < 10) {
        System.out.println(i);
        i++;
    }
    

    プログラムはiカウント変数を10回印刷するので,フロー方式で容易に実現できる.ストリームにはdoWhileメソッドはありませんが、limitメソッドを使用すると次のことができます.
    Stream integers = Stream
      .iterate(0, i -> i + 1);
    integers
      .limit(10)
      .forEach(System.out::println);
    

    同じ機能は、より少ないコードで実装されるが、limit()メソッドを呼び出すことは、ストリームオブジェクト上でdoWhile()メソッドを使用するほど記述的ではない.
    まとめ
    この文書では、ストリームAPIを使用して無限ストリームを作成する方法について説明します.limit()のような変換方法と一緒に使用すると、いくつかのシーンをより理解しやすく実現することができます.怠惰実行は実際の応用に非常に有用であり,無限流と組み合わせて問題を簡単にする.