ストリームAPI最適化されたコードを使用します

宣言型データ収集プロセスの流れ特性は、許可コードはシンプルで読みやすくなるので、新機能のJava8主にラムダ式と流れ、ストリームやラムダ式は、と組み合わせて使用​​する場合

コードストリームを簡素化する方法を増幅するストローク、

需要があれば、データベースクエリの必要性は、料理の過程であることを:

  • スクリーニング未満400カロリー料理
  • 料理は、ソートしたうちのスクリーニング
  • 注文後の名前の料理を取得します。
料理:Dish.java
public class Dish {
    private String name;
    private boolean vegetarian;
    private int calories;
    private Type type;

    // getter and setter
}
复制代码
実施前Java8
private List<String> beforeJava7(List<Dish> dishList) {
        List<Dish> lowCaloricDishes = new ArrayList<>();
        
        //1.筛选出卡路里小于400的菜肴
        for (Dish dish : dishList) {
            if (dish.getCalories() < 400) {
                lowCaloricDishes.add(dish);
            }
        }
        
        //2.对筛选出的菜肴进行排序
        Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
            @Override
            public int compare(Dish o1, Dish o2) {
                return Integer.compare(o1.getCalories(), o2.getCalories());
            }
        });
        
        //3.获取排序后菜肴的名字
        List<String> lowCaloricDishesName = new ArrayList<>();
        for (Dish d : lowCaloricDishes) {
            lowCaloricDishesName.add(d.getName());
        }
        
        return lowCaloricDishesName;
    }
复制代码
Java8の実施後
 private List<String> afterJava8(List<Dish> dishList) {
        return dishList.stream()
                .filter(d -> d.getCalories() < 400)  //筛选出卡路里小于400的菜肴
                .sorted(comparing(Dish::getCalories))  //根据卡路里进行排序
                .map(Dish::getName)  //提取菜肴名称
                .collect(Collectors.toList()); //转换为List
    }
复制代码

すべて1で、その足をドラッグしない、書くため、元の必要性24を達成するために機能コードは今だけです5完成するライン

次のように楽しそうに新たな需要がある。この時点で要件を完了し、新しい要件は次のとおりです。

  • データベースクエリの料理は料理の種類に応じて分類され、それが返すMap<Type, List<Dish>>結果を

これはjdk8前頭皮に間違いだった場合

実施前Java8
private static Map<Type, List<Dish>> beforeJdk8(List<Dish> dishList) {
    Map<Type, List<Dish>> result = new HashMap<>();

    for (Dish dish : dishList) {
        //不存在则初始化
        if (result.get(dish.getType())==null) {
            List<Dish> dishes = new ArrayList<>();
            dishes.add(dish);
            result.put(dish.getType(), dishes);
        } else {
            //存在则追加
            result.get(dish.getType()).add(dish);
        }
    }

    return result;
}
复制代码

幸い、jdk8ストリームがあり、もはや処理要件の複雑なセットを心配する必要はありません

実施後Java8
private static Map<Type, List<Dish>> afterJdk8(List<Dish> dishList) {
    return dishList.stream().collect(groupingBy(Dish::getType));
}
复制代码

、需要を解決するためのコードの行で叫んで助けることができなかったStream API牛がバーの流れを見るために力を与えられ、次の詳細な流れになります

デビューフロー

フローとは何ですか

ソース・ストリームによって生成された要素の配列が支持体からのデータ処理操作であり、ソースは、アレイ、ファイル、関数のセットであることができます。フローは、要素のコレクションではありません、それはデータのデータ構造ではありません保存されていない、その主な目的は、計算することです。

ストリームを生成する方法

フロー生成5つの主要な方法があります

  • セットを生成することにより、最も一般的なアプリケーションの1
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream();
复制代码

設定されたstreamストリームを生成する方法

  • 配列によって生成されました
    int[] intArr = new int[]{1, 2, 3, 4, 5};
    IntStream stream = Arrays.stream(intArr);
    复制代码

Arrays.streamフロー生成方法、及びプロセスのストリームが生成された値のストリームである[すなわちIntStream]の代わりにStream<Integer>パフォーマンスを向上させるために、梱包を開梱の数値フロー計算処理を使用しないようにそれを追加します。Stream API提供mapToIntmapToDoublemapToLong3つの方法が、すなわち、オブジェクトストリームは、[ Stream<T>提供しつつ]、値の対応するストリームに変換されるboxedオブジェクトに数値流れの方法を

  • 値を生成します
    Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
    复制代码

ストリームを生成する方法、によって方法空気の流れを生成することができますStreamofStreamempty

  • ファイルの生成により、
    Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())
    复制代码

Files.lineフロー法を得、得られたストリームをファイルにライン毎に与えられます

  • 関数発生器によって提供されるiterategenerate2つの静的メソッドは、関数から生成されたストリーム
    • イテレータ
    Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(5);
    复制代码
    iterate方法は、第2の動作の関数として、2つのパラメータ最初の初期値をとるiteratorストリームが無限に流れるされて生成されたlimitトランケートされた対流方法もわずか5発生します、
    • 発生器
    Stream<Double> stream = Stream.generate(Math::random).limit(5);
    复制代码
    generateこの方法は、パラメータの型がメソッドであり、一つのパラメータをとりSupplier<T>流量値を提供することによって。generateストリームの流れが無限に発生し、従ってによってれるlimit実施対流切り捨て

操作タイプの流れ

操作種別は、2つの主要な流れに分割されています

  • ストリーム続く中間演算は、ゼロ以上の中間の動作であってもよいです。その主な目的は、データマッピング/フィルタリングのいくつかの学位を作り、流れを開くことですし、次の操作を使用して、新しいストリームを返します。このような動作は、実際の必要性は、以下の共通の中間体の動作が導入されなければならない、端末トラバース操作されるまで待機するだけこのような方法を呼び出し、ストリームの実際の開始を横断しない、不活性であるfiltermap
  • 端末操作ストリームは、操作が行われた場合、ストリームはストリームしたがってもう一度で生成されたソース・データのストリームを横断する必要性を横断することができ、それはもはや動作することができない、閉鎖された、唯一つの端末の動作を有しています。行っターミナルの操作は、ストリームの本当の始まりを横断します。すぐ下に記載されるようにcountcollect

ストリーミングを使用します

導入された端末操作と中間操作を使用してストリームに

中級操作

フィルタースクリーニング
 List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
 integerList.stream().filter(i -> i > 3).forEach(System.out::println);
复制代码

使用してfilter条件付きのスクリーニング方法を、filterメソッドパラメータが条件であります

個別の削除重複要素
List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
integerList.stream().distinct().forEach(System.out::println);
复制代码

distinct方法迅速な除去繰り返しエレメント

指定された制限ストリームの数を返します。
List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
integerList.stream().limit(3).forEach(System.out::println);
复制代码

limitリターンフロー方式の指定された数は、limitパラメータ値がでなければならない>=0、それ以外の場合は、例外がスローされます

スキップストリーム要素をスキップ
 List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
 integerList.stream().skip(2).forEach(System.out::println);
复制代码

skipエレメンタリストリームスキッピングの方法であって、上記の例の前に2つの要素をスキップし、印刷結果2,3,4,5skipパラメータ値が必要があり>=0、そうでない場合は、例外がスローされます

地図フローマッピング

いわゆるフローマッピングは、他の受光素子に要素をマッピングすることです

List<String> stringList = Arrays.asList("Java 8", "Lambdas",  "In", "Action");
stringList.stream().map(String::length).forEach(System.out::println);
复制代码

map完全なマッピング方法、例えば完了String -> Integerマッピングの、上記の実施例による前map処理を完了するためにDish->Stringマッピングを

flatMapストリーム変換

ストリームの各値は、別のストリームに変換されます。

List<String> stringList = Arrays.asList("Hello", "World");
List<Stream<String>> str = stringList.stream()
        .map(world -> world.split(" "))
        .flatMap(Arrays::stream)
        .distinct()
        .collect(Collectors.toList());
复制代码

map(world -> world.split(" "))戻り値Stream<String[]>は、我々は結果が得られると考えるStream<String>ことができ、flatMapメソッド完了Stream<String[]> ->Stream<String>変換を

要素が一致します

これは3つの方法の一致を提供します

  • allMatchすべての一致
    List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
    if (integerList.stream().allMatch(i -> i > 3)) {
        System.out.println("值都大于3");
    }
    复制代码

することによりallMatch達成する方法

  • anyMatch 1試合
    List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
    if (integerList.stream().anyMatch(i -> i > 3)) {
        System.out.println("存在大于3的值");
    }
    复制代码
    に相当
    for (Integer i : integerList) {
        if (i > 3) {
            System.out.println("存在大于3的值");
            break;
        }
    }
    复制代码

図3は、プリントの現在値よりも大きいjava8ことによりanyMatch、この方法を達成します

  • noneMatchすべての不一致
    List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
    if (integerList.stream().noneMatch(i -> i > 3)) {
        System.out.println("值都小于3");
    }
    复制代码
    することによりnoneMatch達成する方法

ターミナル事業

統計フロー内の要素の数
  • countで
    List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
    Long result = integerList.stream().count();
    复制代码

使用することによりcount、フロー方式の要素数の統計を

  • カウントすることにより
    List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
    Long result = integerList.stream().collect(counting());
    复制代码

素子数の統計の最終的な方法とcollect組み合わせて使用される場合に特に有用です

求めます

それは見つけるための2つの方法が用意されてい

  • まず、検索関数は、FindFirst

    List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
    System.out.println(integerList.stream().filter(i -> i > 3).findFirst());
    复制代码

    よるfindFirst3とプリントよりも大きい最初の要素への参照方法

  • ランダムfindAnyを探します

    List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
    System.out.println(integerList.stream().filter(i -> i > 3).findAny());
    复制代码

    findAnyため、内部最適化三およびプリント、より大きな要素の1つにルックアップ方式と、3つ以上の最初の要素が大きい満たすことが見出された場合には、方法及び結果終了したfindFirst結果と同じように。それは提供しfindAny、並列ストリームのより有効に活用するためのメソッドをfindFirst[この記事では、並行して並列ストリームを紹介しません]の方法は、より限定されました

結合ストリーム要素を減らします

私たちは一連の値を合計したものと

  • jdk8前

    int sum = 0;
    for (int i : integerList) {
    sum += i;
    }
    复制代码
  • 削減jdk8によって処理された後、

    int sum = integerList.stream().reduce(0, (a, b) -> (a + b));
    复制代码

    行が完了することができ、この方法は、速記参照として使用してもよいです。

    int sum = integerList.stream().reduce(0, Integer::sum);
    复制代码

    reduceそれは、2つのパラメータ、ここでは初期値受け入れ0BinaryOperator<T> accumulator二つの要素には、に加えて、新たな価値を生み出すために結合するreduce方法と値の初期化メソッドをオーバーライドしません

最小および最大流量を求めます
  • 最小の最小値/最大値の最大値を取得することにより
    Optional<Integer> min = menu.stream().map(Dish::getCalories).min(Integer::compareTo);
    Optional<Integer> max = menu.stream().map(Dish::getCalories).max(Integer::compareTo);
    复制代码
    min、最小流量を求めるmax引数で、最大流量を求めますComparator<? super T> comparator
  • 最小minBy / maxByの最大値を取得することにより
    Optional<Integer> min = menu.stream().map(Dish::getCalories).collect(minBy(Integer::compareTo));
    Optional<Integer> max = menu.stream().map(Dish::getCalories).collect(maxBy(Integer::compareTo));
    复制代码

minBy、最小流量を求めるmaxBy引数で、最大流量を求めますComparator<? super T> comparator

  • 最小値と最大取得することにより削減
    Optional<Integer> min = menu.stream().map(Dish::getCalories).reduce(Integer::min);
    Optional<Integer> max = menu.stream().map(Dish::getCalories).reduce(Integer::max);
    复制代码

理解することは簡単で、最小の最大値を取得するための最後の方法を好みます

summingIntを合計することによって、
int sum = menu.stream().collect(summingInt(Dish::getCalories));
复制代码

に相当することによりreduce

int sum2 = menu.stream().map(Dish::getCalories).reduce(0, Integer::sum);
复制代码

最初のアプローチを使用することを好む、reduce合計はそれが比較より宣言的である場合、データ・タイプdoublelong次いでスルーsummingDoublesummingLong加算方法

averagingIntを平均化することにより
double average = menu.stream().collect(averagingInt(Dish::getCalories));
复制代码

データを入力するとdoublelong次に介してaveragingDoubleaveragingLong平均化のための方法

同時にsummarizingInt合計、平均、最大値、最小値を取得することにより
IntSummaryStatistics intSummaryStatistics = menu.stream().collect(summarizingInt(Dish::getCalories));
double average = intSummaryStatistics.getAverage();  //获取平均值
int min = intSummaryStatistics.getMin();  //获取最小值
int max = intSummaryStatistics.getMax();  //获取最大值
long sum = intSummaryStatistics.getSum();  //获取总和
复制代码

データ型の場合doublelongその後を通じてsummarizingDoublesummarizingLong方法

groupingByによってグループ化された高度な
Map<Type, List<Dish>> result = dishList.stream().collect(groupingBy(Dish::getType));
复制代码

中にcollect入ってくるプロセスgroupingBy群、前記groupingByプロセスパラメータは、分類の関数です。また、入れ子にすることができgroupingBy、マルチクラス分類器を

Map<Type, List<Dish>> result = menu.stream().collect(groupingBy(Dish::getType,
        groupingBy(dish -> {
            if (dish.getCalories() <= 400) return CaloricLevel.DIET;
                else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                else return CaloricLevel.FAT;
        })));
复制代码
partitioningByによって高度なパーティション

パーティションは、trueとfalseに基づいて分類特殊なグループであり、その結果は、2つのグループにまで戻りました

Map<Boolean, List<Dish>> result = menu.stream().collect(partitioningBy(Dish :: isVegetarian))
复制代码

に相当

Map<Boolean, List<Dish>> result = menu.stream().collect(groupingBy(Dish :: isVegetarian))
复制代码

この例では、パーティション少し明白な例を変更する必要はありませんでしたでも、ゾーニングと分類、との違いが表示されないことがあります。

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Map<Boolean, List<Integer>> result = integerList.stream().collect(partitioningBy(i -> i < 3));
复制代码

戻り値は、結合のブールタイプが残っているが、その分類は、範囲に従って分類され、範囲に応じて、ゾーニングの分類を処理するためのより適切な

要素を結合することによりスプライシングされたストリーム
String result = menu.stream().map(Dish::getName).collect(Collectors.joining(", "));
复制代码

ない場合、デフォルトによるmapスプライシングのマッピング処理方法toStringメソッドによって返される文字列、要素パラメータの区切りを接合するための方法であって、結果の文字列が文字列である場合に可読性が強くない指定しません

概要

使用するとStream API、コードの可読性を向上させながら、コードを簡略化することができ、かつ迅速にプロジェクトに使い切ります。学ばなかった理由Stream APIの前には、内のアプリケーションの多くで私を書いた人たちはLambdaStream API彼の足を飛ぶことを望んでいました。私は彼を愛するかもしれないと思う[喜喜]。時間の宣言型と命令型プログラミングのミックスを使用しないように注意し、同時に、ブラシの数日前には、segmentブラシに:

imango 兄はそれが正しい、と 宣言型プログラミングのフックを使用しないでください文法は命令型プログラミングを乾燥します

おすすめ

転載: juejin.im/post/5d8226d4e51d453c135c5b9a