Java 8に追加されました.ストリーム


Cover image by Samuel Sianipar on Unsplash


多くのプログラミングタスクをデータ処理として記述することができます.すなわち、フィルタ、変換、グループのように変更したい値のコレクションを持っています.Java 8まで、このタスクは本当に痛かったです(複数のループを必要としました).幸いにも新しい概念-ストリームです.
これはJava 8の新機能の3つの部分シリーズです.
  • ストリーム( current )
  • オプションのクラス(すぐ)
  • java 8は,データ処理のための新しいパイプライン機構を導入した.通常、パイプラインやアセンブリラインと比較されます.なぜなら、引数として起動するとデータ収集を提供し、それを変更して別の出力を取得する操作を通過するからです.
    どのようなストリーム機能の例を以下の例を参照してください.これは“標準”とストリームベースのアプローチで作られた同じタスクを比較します.
    List<Tshirt> tshirtCollection = shop.getTshirtCollection();
    List<String> selectedTshirts = new ArrayList<String>();
    
    // without Streams
    for(Tshirt tshirt: tshirtCollection){
      if (tshirt.getColor().equals("RED")) {
       if (tshirt.getSize().equals("M")) {
        if (new BigDecimal(50).compareTo(tshirt.getPrice() > 0){
          selectedTshirts.add(tShirt.getName().toUpperCase());
       }
      }
    }
    
    //with Streams
    tshirtCollection.stream()
            .filter(tshirt -> tshirt.getColor().equals("RED"))
            .filter(tshirt -> tshirt.getSize().equals("M"))
            .filter(tshirt -> new BigDecimal(50).compareTo(tshirt.getPrice() > 0)
            .map(s -> s.getName().toUpperCase())
            .collect(Collectors.toList());
    
    たとえ私がまだ構文を導入していないとしても、我々はすでに主要な利点を見ることができます.まず第一に、コードは非常に簡単でクリーナーです.そして、たとえ我々がすべてのオペレーターをまだ知らないとしても、彼らは理解しやすいです.
    すべてのこれらのタスクをカバーするためにjava.util.stream 含むStream クラス.上の例ではstream ()がコレクションに呼び出され、ストリームの結果となります.これはTシャツオブジェクトのストリームがリストから作成されたことを意味します👕.
    ストリームに関連するすべてのメソッドを3つのグループに分類できます.
  • 流水法
  • ストリーム操作メソッド(中間メソッド)
  • ストリームターミナルメソッド.

  • 流水法
    最初にオブジェクトストリームを操作する前に、作成する必要があります.Javaのアップデートでは、OracleはCollection このインターフェイス(リスト、マップ、セットのような)を実装するオブジェクトをstreamに変換するname stream ()とのインタフェース.
    上記のステートメントでは、ArrayListまたはHashSetのようなオブジェクトのみがストリームに変換できることを示します.
    また、配列クラスから静的メソッドを使用して配列から生成することもできます.stream ( T []配列)
    String[] arrayOfExpressions = {"Hello World!", "Hi everyone!", "Good Morning!", "How u doin'?"};
    
    Stream<String> streamfromArray = Arrays.stream(arrayOfExpressions);
    
    我々がオブジェクトのリストを持っていないならば、我々は2から始まる整数の無限の流れをつくることができて、3によって増分されます.そのためには、stream class - iterate ()の静的メソッドを使用できます.
    Stream<Integer> infiniteStream = Stream
                                      .iterate(2, i -> i + 3)
                                      .limit(10);
    
    無限ループを終了するにはlimit ()ステップが必要です.
    ストリームを作成する別の方法はstreamクラスのstatic generate ()メソッドを使うことです.コードの下には、各要素が“text”文字列である10個の要素ストリームが生成されます.
    Stream<String> stream = Stream
                              .generate(() -> "text")
                              .limit(10);
    

    ストリーム操作メソッド(中間メソッド)
    ストリームが作成されると、その要素に複数の操作を行うことができます.このための鍵となる概念は、一緒に連鎖されたいくつかの操作を作成することができます.各演算子はストリームクラスの新しいインスタンスを返します.
    ここでは、ストリームで実行できるいくつかの(しかし、すべての)操作のリストを示します.

  • filter () - SQLのWHERE句と同様に動作します.
  • tshirtCollection.stream()
            .filter(tshirt -> tshirt.getColor().equals("RED"))
    

  • map () -ストリーム内の各要素を変換するときに使用します.たとえば、オブジェクト内のフィールド(TSeeクラスからの名前)から値を抽出したり、1つの値を別の(キログラムからポンド)に変換する場合など.
  • Stream<String> tshirtNameStream = tshirtCollection.stream()
                                        .map(Tshirt::getName);
    
    Stream<Double> tshirtPoundWeightStream = tshirtCollection.stream()
                                        .map(Tshirt::getKilogramWeight)
                                        .map(kg -> kg/2.205);
    

  • flatmap () -この操作はmap ()と非常に似ていますが、"flatten "タスクも実行します.map ()演算の本体が値または値の配列を返すときに必要です(以前と同じ値ではありません).このようなタスクを実行するためにmap ()操作を使用すると、ストリームのストリームを受け取ります.しかし、flatmap ()を使用すると、これらのストリームは全て単一ストリームに結合されます.
  • String[] arrayOfExpressions = {"Hello World!", "Hi everyone!", "Good Morning!", "How u doin'?"};
    
    Stream<Stream<String>> streamOfStreamsOfWords = Arrays.stream(arrayOfExpressions)
                                                      .map(exp -> exp.split("\\s+"));
    
    Stream<String> streamOfWords = Arrays.stream(arrayOfExpressions)
                                                      .flatMap(exp -> exp.split("\\s+"));
    

  • sorted () - SQLのOrder by句と同様に働きます.このメソッドに引数を指定しないと、すべてのレコードが自然順に昇順になります.しかし、我々が入力比較器ならば.引数としてreverseorder ()を使用します.
  • Stream<Integer> infiniteStream = Stream
                                      .iterate(2, i -> i + 3)
                                      .limit(10);
    
    Stream<Integer> ascOrderedStream = infiniteStream.sorted();
    
    Stream<Integer> dscOrderedStream = infiniteStream.sorted(Comparator.reverseOrder());
    
    文字列や数字をソートする必要がある場合には、トリックを行うかもしれませんが、複雑なオブジェクトを注文しない場合は、どのオブジェクトフィールドをソートに使用するかを示すComperatorオブジェクトを作成する必要があります.
    Stream<Tshirt> ascOrderedTshirts = tshirtCollection.stream()
                                        .sorted(Comparator.comparing(Tshirt::getSize));
    
    Stream<Tshirt> dscOrderedTshirts = tshirtCollection.stream()
                                        .sorted(Comparator.comparing(Tshirt::getSize).reversed());
    

  • array () -重複した要素を持たないストリームを返します.

  • ストリーム端末方式
    ストリーム上のすべてのこれらの変換操作を実行した後、我々はそれの結果を見たい.Streamクラスはラッパーですので、値を取得するには以下のアクションを実行する必要があります.

  • aggregate () - streamを要素のリストと比較することができますので、この操作を使用してストリームをリスト(またはその他のコレクションインスタンス)に変換できます.引数を渡すことでCollector オブジェクトの結果を指定できます.
  • たとえば、静的メソッドコレクタを使用する場合.オブジェクトのリストを取得したり、コレクタを使用したりします.toset ()はsetオブジェクトになります.
    List<Tshirt> redTshirtsList = tshirtCollection.stream()
                                .filter(tshirt -> tshirt.getColor().equals("RED"))
                                .collect(Collectors.toList());
    
    Set<Tshirt> mediumTshirtSet = tshirtCollection.stream()
                                    .filter(tshirt -> tshirt.getSize().equals("M"))
                                    .collect(Collectors.toSet());
    
    ビルドインコレクタメソッドとは別に、より洗練されたアプローチを使用できます.コレクタを使用できます.tocolaction ()メソッドは、コレクションオブジェクトの型を指定することができます.
    Set<Tshirt> mediumTshirtSet = tshirtCollection.stream()
                                    .filter(tshirt -> tshirt.getSize().equals("M"))
                                    .collect(toCollection(HashSet::new));
    
    しかし、我々がこの方法ですることができるすべてでありません.例えば、私たちは(SQLでのように)結果を特定のフィールドによってカウント、最大値を得るためにグループ化することができます.または、特定のフィールドからすべての値を合計することができます.これらの他の例はOracle article .
  • toArray () -以前のものと似ていますが、ここではコレクションではなくオブジェクトの配列になります.
  • foreact () -このメソッドを使用すると、オブジェクトを返すことはありません(返り値はvoidです).たとえば、コンソールで名前を印刷したり、各要素に対してアクションを実行できます.
  • tshirtCollection.stream()
                 .filter(tshirt -> tshirt.getColor().equals("RED"))
                 .map(Tshirt::getName)
                 .forEach(System.out::println);
    
    そしてそれです.この記事で、私はJavaストリームの表面にしか触れませんでしたが、それは良い点です.あなたがもっと知りたいならば、公式ドキュメンテーションをチェックして、それを提供することができるすべての能力を知っているようにまわりで遊んでください.

    参考文献
  • Processing Data with Java SE 8 Streams, Part 1 on oracle.com
  • Part 2: Processing Data with Java SE 8 Streams on oracle.com
  • The Java 8 Stream API Tutorial | Baeldung on baeldung.com
  • Java 8: Replace traditional for loops with IntStreams on deadcoderising.com