Java 8の新しい特性のStreamストリーム(六)収集


私たちの前の5つの文章は基本的に1つの集合を1つのストリームに変えて、それから対流して操作すると言っていますが、実はこの操作が一番多いですが、時にはストリームからいくつかの要素を集めて、集合的に戻る必要があります.私たちはこのような逆操作を収集と言います.
ストリームAPIも対応する方法を提供してくれた.
ストリームで収集機能を使用する方法
まず、ストリームAPIが提供する方法を見てみましょう.
public interface Stream extends BaseStream> {
//...          
 R collect(Supplier supplier,
                  BiConsumer accumulator,
                  BiConsumer combiner);
 R collect(Collector super T, A, R> collector);
}

ストリーミングAPIでは2種類提供されていますが、分析してみましょう.
R collect(Collector super T, A, R> collector);
ここで、Rは結果のタイプを指定し、Tは呼び出しストリームの要素のタイプを指定する.内部蓄積のタイプはAで指定します.collectorFuncは収集プロセスがどのように実行されるかを指定するコレクタであり、collect()メソッドは端末メソッドである.
カスタマイズされたcollectorFuncは基本的にあまり使いませんが、皆さんの知識面を広げるために、Collector、Because it’s my styleについて簡単に話しましょう.Collectorインタフェースはjava.util.streamパッケージにあるという声明で、その顔は次のようになっています.
package java.util.stream;
public interface Collector {
      Suppliersupplier();
BiConsumeraccumulator();
BinaryOperatorcombiner();
Functionfinisher();
}

ここで、T、A、Rの意味は上記と同様の R ,T 。 A である.
しかし、この記事では、JDKが強力な方法を提供してくれたため、java.util.streamの下にあるCollectorsクラスにあり、本編では主にCollectorsを使用して収集機能を実現しています.Collectorsクラスは最終クラスであり、多くの静的コレクタ方法を提供しています.彼を借りて、私たちは基本的に様々な複雑な機能を実現することができます.
toListとtoSetの方法を見てみましょう.
public static   Collector> toList()
public static  Collector> toSet()

ここで、Collectors#toList()が返すコレクタは、ストリーム中の要素を1つのListに収集することができ、Collectors#toSet()が返すコレクタは、ストリーム中の要素を1つのSetに収集することができる.たとえば、リストに要素を収集したい場合は、steam.collect(Collectors.toList)を使用します.
次に、私たちの王者の栄光チームの経済例を修正して、スタープレイヤーと現在獲得した金貨の数をリストに集めて、出場した英雄をセットに集めます.
#                 
public class HeroPlayerGold {
    /**         */
    private String hero;
    /**    ID */
    private String player;
    /**        */
    private int gold;


    public HeroPlayerGold(String hero, String player, int gold) {
        this.hero = hero;
        this.player = player;
        this.gold = gold;
    }

    @Override
    public String toString() {
        return "HeroPlayerGold{" +
                "hero='" + hero + '\'' +
                ", player='" + player + '\'' +
                ", gold=" + gold +
                '}';
    }
//  get/set
}

#     
public class Hero {
    /**         */
    private String hero;

    public Hero(String hero) {
        this.hero = hero;
    }

    @Override
    public String toString() {
        return "Hero{" +
                "hero='" + hero + '\'' +
                '}';
    }
//  get/set
}

#   
public class Main {
    public static void main(String[] args) {
        learnCollect();
    }

    private static void learnCollect() {
        List lists = new ArrayList<>();
        lists.add(new HeroPlayerGold("  ", "RNG-Letme", 100));
        lists.add(new HeroPlayerGold("   ", "RNG-Xiaohu", 300));
        lists.add(new HeroPlayerGold("  ", "RNG-MLXG", 300));
        lists.add(new HeroPlayerGold("   ", "RNG-UZI", 500));
        lists.add(new HeroPlayerGold("  ", "RNG-Ming", 500));

        List playerGolds = lists.stream()
                .map(plary -> new PlayerGold(plary.getPlayer(), plary.getGold()))
                .collect(Collectors.toList());
        System.out.println("============PlayerGold begin==============");
        playerGolds.forEach(System.out::println);
        System.out.println("============PlayerGold end================
"); Set heroes = lists.stream().map(player -> new Hero(player.getHero())).collect(Collectors.toSet()); System.out.println("============Hero begin=============="); heroes.forEach(System.out::println); System.out.println("============Hero end================"); } }

出力ログ:
============PlayerGold begin==============
PlayerGold{player='RNG-Letme', gold=100}
PlayerGold{player='RNG-Xiaohu', gold=300}
PlayerGold{player='RNG-MLXG', gold=300}
PlayerGold{player='RNG-UZI', gold=500}
PlayerGold{player='RNG-Ming', gold=500}
============PlayerGold end================

============Hero begin==============
Hero{hero='  '}
Hero{hero='  '}
Hero{hero='  '}
Hero{hero='   '}
Hero{hero='   '}
============Hero end================

ここを見て、皆さんは流APIの威力を感じましたか?ヒントとして、ツールクラスをカプセル化し、FastJsonというものを組み合わせて使用します!本当に使いやすいですね.実際には、集合からストリームにデータを移動したり、ストリームから集合にデータを移動したりする能力は、ストリームAPIがストリームを介して集合を操作し、ストリームを集合に再パッケージすることができるため、ストリームAPIが提供する強力な特性です.また,条件が適切な場合には,フロー操作を並列に発生させ,効率を向上させる.
次に2つ目の方法を分析します
 R collect(Supplier supplier,
                 BiConsumer accumulator,
                 BiConsumer combiner);

私たちの2番目のバージョンの収集方法は、主に収集の過程で、より多くの制御を与えることができます.ここでsupplierは、結果を保存するオブジェクトの作成方法を指定します.たとえば、ArrayListを結果のセットとして使用するには、そのコンストラクション関数を指定する必要があります.accumulator関数は、1つの要素を結果に追加し、combiner関数は2つの部分をマージした結果です.
皆さんは発見したでしょう.彼の仕事のやり方は私たちの3編目で縮小操作を紹介したときのreduceの方法と似ています.これらはいずれも無状態で介入しなければならず,関連性が必要であり,3つの制約条件が欠けてはならない.Supplierjava.util.functionパッケージの関数インタフェースです.
@FunctionalInterface
public interface Supplier {
    T get();
}

1つのget()のみであり、パラメータはなく、collect()メソッドではRタイプのオブジェクトが返され、get()メソッドではセットへの参照が返されます.
accumulator、combinerのタイプはBiConsumerで、java.util.functionパッケージの関数インタフェースでもあります.
@FunctionalInterface
public interface BiConsumer {
    void accept(T t, U u);
}

ここで、t,uは何らかのタイプの操作を実行し、accumulatorにとって、tはターゲットセットを指定し、uはそのセットに追加する要素を指定する.combinerの場合、tとuはマージする2つの集合を指定します.
前の例を変更して、lambdaとlambdaを使用していない場合の違いも詳しく説明します.
これはlambdaを使用する前のものではありません.
private static void learnCollect() {
        List lists = new ArrayList<>();
        lists.add(new HeroPlayerGold("  ", "RNG-Letme", 100));
        lists.add(new HeroPlayerGold("   ", "RNG-Xiaohu", 300));
        lists.add(new HeroPlayerGold("  ", "RNG-MLXG", 300));
        lists.add(new HeroPlayerGold("   ", "RNG-UZI", 500));
        lists.add(new HeroPlayerGold("  ", "RNG-Ming", 500));


        lists.stream().collect(new Supplier>() {
                                   @Override
                                   public HashSet get() {
                                       return new HashSet<>();
                                   }
                               },//     
                new BiConsumer, HeroPlayerGold>() {
                    @Override
                    public void accept(HashSet heroPlayerGolds, HeroPlayerGold heroPlayerGold) {
                        heroPlayerGolds.add(heroPlayerGold);
                    }
                },//     
                new BiConsumer, HashSet>() {
                    @Override
                    public void accept(HashSet heroPlayerGolds, HashSet heroPlayerGolds2) {
                        heroPlayerGolds.addAll(heroPlayerGolds2);
                    }
                }//     
        ).forEach(System.out::println);
    }

lambdaを使わない前に、目まぐるしく見えますが、彼は実は私たちが非常に強力な機能を実現するのに役立つと言わざるを得ません.私たちがカスタマイズした収集過程は、すべてこいつに任せることができます.私たちはlambdaで整理します.
private static void learnCollect() {
        List lists = new ArrayList<>();
        lists.add(new HeroPlayerGold("  ", "RNG-Letme", 100));
        lists.add(new HeroPlayerGold("   ", "RNG-Xiaohu", 300));
        lists.add(new HeroPlayerGold("  ", "RNG-MLXG", 300));
        lists.add(new HeroPlayerGold("   ", "RNG-UZI", 500));
        lists.add(new HeroPlayerGold("  ", "RNG-Ming", 500));


        lists.stream().collect(() -> new HashSet<>(),
                                (set,elem)->set.add(elem),
                                (setA,setB)->setA.addAll(setB)
        ).forEach(System.out::println);
        
}

皆さんはこれで終わりだと思いますか?メソッド参照とコンストラクション関数参照を使用して、以下を簡略化することもできます.
private static void learnCollect() {
        List lists = new ArrayList<>();
        lists.add(new HeroPlayerGold("  ", "RNG-Letme", 100));
        lists.add(new HeroPlayerGold("   ", "RNG-Xiaohu", 300));
        lists.add(new HeroPlayerGold("  ", "RNG-MLXG", 300));
        lists.add(new HeroPlayerGold("   ", "RNG-UZI", 500));
        lists.add(new HeroPlayerGold("  ", "RNG-Ming", 500));


        lists.stream().collect(HashSet::new,
                               HashSet::add,
                               HashSet::addAll
        ).forEach(System.out::println);
}

まとめてみる
本編では、Streamの収集操作について説明しますが、いくつかのこの入門操作があれば、私はあなたが私の発展の過程で拡張点を発見したと信じています.supplier、accumulator、combinerにかかわらず、中に特別な操作を入れて、あなたたちのさまざまな要求を満たすことができます.
もう一つの点は、Collectorsという最終クラスを忘れないでください.中にはすでに多くの強力な静的方法が提供されています.もしあなたたちが特別なニーズに遭遇したら、まず考えなければならないのはCollectorsです.もし中の方法があなたの要求を実現できないなら、第2のバージョンのcollect()方法でカスタム収集プロセスを実現することを考えてみましょう.