第9篇 用流收集資料----- 歸約和彙總
阿新 • • 發佈:2018-12-16
/** * 為了說明從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()); } }