1. 程式人生 > >第9篇 用流收集資料----- 歸約和彙總

第9篇 用流收集資料----- 歸約和彙總

/**
 * 為了說明從Collectors工廠類中能創建出多少種收集器例項,我們重用一下前面的例
 * 子:包含一張佳餚列表的選單!
 * 就像你剛剛看到的,在需要將流專案重組成集合時,一般會使用收集器(Stream方法collect
 * 的引數)。再寬泛一點來說,但凡要把流中所有的專案合併成一個結果時就可以用。這個結果可以
 * 是任何型別,可以複雜如代表一棵樹的多級對映,或是簡單如一個整數——也許代表了選單的熱
 * 量總和。這兩種結果型別我們都會討論
 */
public class Demo01 {
    public static void main(String[] args) {
        List<Dish> menues = Arrays.asList(new Dish("rice", true, 10000, Dish.Type.FISH), new Dish("meate", false, 20000, Dish.Type.FISH), new Dish("dog", true, 30000, Dish.Type.FISH));
//        test01(menues);
//        test02(menues);
//        test03(menues);
//        test04(menues);
//        test05(menues);
        test06(menues);
    }


    /**
     * 把流中所有的元素收集到一個List中
     */
    public static void test01(List<Dish> menues) {
        List<Dish> dishes = menues.stream().collect(toList());

    }

    /**
     * 利用counting工廠方法返回的收集器,數一數選單裡有多少
     * 種菜
     *
     * @param menues
     */
    public static void test02(List<Dish> menues) {
        Long count = menues.stream().collect(counting());
        System.out.println(count);
        long count2 = menues.stream().count();
        System.out.println(count2);
    }

    /**
     * 查詢流中的最大值和最小值:
     * 假設你想要找出選單中熱量最高的菜
     * 你可能在想Optional<Dish>是怎麼回事。要回答這個問題,我們需要問“要是menu為空
     * 怎麼辦”。那就沒有要返回的菜了!Java 8引入了Optional,它是一個容器,可以包含也可以不
     * 包含值。這裡它完美地代表了可能也可能不返回菜餚的情況
     *
     * @param menues
     */
    public static void test03(List<Dish> menues) {
        Optional<Dish> optionalDish = menues.stream().collect(maxBy(comparing(Dish::getCalories)));
        if (optionalDish.isPresent()) {
            System.out.println("熱量最大值為:" + optionalDish.get().getCalories());
        } else {
            System.out.println("沒有菜啊,比啥比!");
        }
        Optional<Dish> optionalDish2 = menues.stream().collect(maxBy(comparingInt(Dish::getCalories)));
        Optional<Dish> optionalDish3 = menues.stream().max(comparing(Dish::getCalories));
        if (optionalDish3.isPresent()) {
            System.out.println("熱量最大值為:" + optionalDish.get().getCalories());
        } else {
            System.out.println("沒有菜啊,比啥比!");
        }
        Optional<Dish> minCalory = menues.stream().min(comparing(Dish::getCalories));
        if (minCalory.isPresent()) {
            System.out.println("熱量最小值為:" + optionalDish.get().getCalories());

        } else {
            System.out.println("沒有菜啊,比啥比!");
        }
    }

    /**
     * 彙總:
     * Collectors類專門為彙總提供了一個工廠方法:Collectors.summingInt。它可接受一
     * 個把物件對映為求和所需int的函式,並返回一個收集器;該收集器在傳遞給普通的collect方
     * 法後即執行我們需要的彙總操作。舉個例子來說,你可以這樣求出選單列表的總熱量
     * 這裡的收集過程如圖6-2所示。在遍歷流時,會把每一道菜都對映為其熱量,然後把這個數
     * 字累加到一個累加器(這裡的初始值0)。
     * Collectors.summingLong和Collectors.summingDouble方法的作用完全一樣,可以用
     * 於求和欄位為long或double的情況。
     *
     * @param menues
     */
    public static void test04(List<Dish> menues) {
        Integer sumCalory = menues.stream().collect(summingInt(Dish::getCalories));
        System.out.println("總熱量為:" + sumCalory);
        int sum = menues.stream().mapToInt(Dish::getCalories).sum();
        System.out.println("總熱量為:" + sum);

    }

    /**
     * 彙總:求平均數
     *
     * @param menues
     */
    public static void test05(List<Dish> menues) {
        Double avgCalory = menues.stream().collect(averagingInt(Dish::getCalories));
        System.out.println(avgCalory);
    }

    /**
     * 彙總:
     * 到目前為止,你已經看到了如何使用收集器來給流中的元素計數,找到這些元素數值屬性的
     * 最大值和最小值,以及計算其總和和平均值。不過很多時候,你可能想要得到兩個或更多這樣的
     * 結果,而且你希望只需一次操作就可以完成。在這種情況下,你可以使用summarizingInt工廠
     * 方法返回的收集器。例如,通過一次summarizing操作你可以就數出選單中元素的個數,並得
     * 到菜餚熱量總和、平均值、最大值和最小值
     *
     * @param menues
     */
    public static void test06(List<Dish> menues) {
        IntSummaryStatistics collectCalory = menues.stream().collect(summarizingInt(Dish::getCalories));
        System.out.println(collectCalory.toString());
        System.out.println("max:" + collectCalory.getMax() + ";min:" + collectCalory.getMin() + ";avg:" + collectCalory.getAverage() + ";sum" + collectCalory.getSum() + ";count" + collectCalory.getCount());
    }
}