Java 8 - 收集器Collectors_归约和汇总
文章目錄
- Pre
- 查找流中的最大值和最小值
- 需求:想要找出熱量最高的菜和熱量最低的菜
- 匯總
- 需求: 求出菜單列表的總熱量
- 需求: 一次操作求出菜單中元素的個(gè)數(shù),并得總和、平均值、最大值和最小值 (summarizingXXX)
- 連接字符串
- 需求 :把菜單中所有菜肴的名稱連接起
Pre
在需要將流項(xiàng)目重組成集合時(shí),一般會(huì)使用收集器( Stream 方法 collect的參數(shù))。再寬泛一點(diǎn)來(lái)說(shuō),但凡要把流中所有的項(xiàng)目合并成一個(gè)結(jié)果時(shí)就可以用。這個(gè)結(jié)果可以是任何類型。
public static List<Dish> menu = Arrays.asList(new Dish("pork", false, 800, Dish.Type.MEAT),new Dish("beef", false, 700, Dish.Type.MEAT),new Dish("chicken", false, 400, Dish.Type.MEAT),new Dish("french fries", true, 530, Dish.Type.OTHER),new Dish("rice", true, 350, Dish.Type.OTHER),new Dish("season fruit", true, 120, Dish.Type.OTHER),new Dish("pizza", true, 550, Dish.Type.OTHER),new Dish("prawns", false, 300, Dish.Type.FISH),new Dish("salmon", false, 450, Dish.Type.FISH));來(lái)看個(gè)簡(jiǎn)單的需求: 利用 counting 工廠方法返回的收集器,統(tǒng)計(jì)菜單中有多少種菜
public static Long howManyDishes(List<Dish> menu) {// return menu.stream().count();return menu.stream().collect(Collectors.counting());}還可以寫得更為直接:
return menu.stream().count();查找流中的最大值和最小值
需求:想要找出熱量最高的菜和熱量最低的菜
public static Optional<Dish> highCa(List<Dish> menu) {Optional<Dish> collect = menu.stream().collect(Collectors.maxBy(Comparator.comparingInt(Dish::getCalories)));return collect;}public static Optional<Dish> lowC(List<Dish> menu) {Optional<Dish> collect = menu.stream().collect(Collectors.minBy(Comparator.comparing(Dish::getCalories)));return collect;}可以使用兩個(gè)收集器, Collectors.maxBy 和Collectors.minBy ,來(lái)計(jì)算流中的最大或最小值。這兩個(gè)收集器接收一個(gè) Comparator 參數(shù)來(lái)比較流中的元素。
可以創(chuàng)建一個(gè) Comparator 來(lái)根據(jù)所含熱量對(duì)菜肴進(jìn)行比較,并把它傳遞給Collectors.maxBy :
Comparator<Dish> dishCaloriesComparator = Comparator.comparingInt(Dish::getCalories);然后進(jìn)行計(jì)算
Optional<Dish> collect = menu.stream().collect(Collectors.maxBy(dishCaloriesComparator ));Optional<Dish> 是怎么回事。要回答這個(gè)問(wèn)題,我們需要問(wèn)“要是 menu 為空怎么辦”。那就沒(méi)有要返回的?了!Java 8引入了 Optional ,它是一個(gè)容器,可以包含也可以不包含值。這里它完美地代表了可能也可能不返回菜肴的情況。
匯總
另一個(gè)常見(jiàn)的返回單個(gè)值的歸約操作是對(duì)流中對(duì)象的一個(gè)數(shù)值字段求和、求平均數(shù)等等。這種操作被稱為匯總操作。讓我們來(lái)看看如何使用收集器來(lái)表達(dá)匯總操作。
Collectors 類專門為匯總提供了一個(gè)工廠方法: Collectors.summingInt 。它可接受一 個(gè)把對(duì)象映射為求和所需 int 的函數(shù),并返回一個(gè)收集器;該收集器在傳遞給普通的 collect 方法后即執(zhí)行我們需要的匯總操作。
需求: 求出菜單列表的總熱量
public static Integer allCal(List<Dish> menu) {Integer collect = menu.stream().collect(Collectors.summingInt(Dish::getCalories));return collect;}收集過(guò)程如下:
在遍歷流時(shí),會(huì)把每一道菜都映射為其熱量,然后把這個(gè)數(shù)字累加到一個(gè)累加器(這里的初始值 0 )。
Collectors.summingLong 和 Collectors.summingDouble 方法的作用完全一樣,可以用于求和字段為 long 或 double 的情況。
但匯總不僅僅是求和;還有 Collectors.averagingInt ,連同對(duì)應(yīng)的 averagingLong 和averagingDouble 可以計(jì)算數(shù)值的平均數(shù):
public static Double avg(List<Dish> menu) {Double collect = menu.stream().collect(Collectors.averagingInt(Dish::getCalories));return collect;}截止到現(xiàn)在,我們使用收集器來(lái)給流中的元素計(jì)數(shù),找到這些元素?cái)?shù)值屬性的最大值和最小值,以及計(jì)算其總和和平均值。
需求: 一次操作求出菜單中元素的個(gè)數(shù),并得總和、平均值、最大值和最小值 (summarizingXXX)
public static IntSummaryStatistics sumInfo(List<Dish> menu) {IntSummaryStatistics collect = menu.stream().collect(Collectors.summarizingInt(Dish::getCalories));return collect;}輸出
summarizingInt這個(gè)收集器會(huì)把所有這些信息收集到一個(gè)叫作 IntSummaryStatistics 的類里,它提供了方便的取值(getter)方法來(lái)訪問(wèn)結(jié)果。
同樣,相應(yīng)的 summarizingLong 和 summarizingDouble 工廠方法有相關(guān)的 LongSummary-Statistics 和 DoubleSummaryStatistics 類型,適用于收集的屬性是原始類型 long 或double 的情況。
連接字符串
joining 工廠方法返回的收集器會(huì)把對(duì)流中每一個(gè)對(duì)象應(yīng)用 toString 方法得到的所有字符串連接成一個(gè)字符串。
需求 :把菜單中所有菜肴的名稱連接起
public static String joinMenu(List<Dish> menu) {return menu.stream().map(Dish::getName).collect(Collectors.joining());}請(qǐng)注意, joining 在內(nèi)部使用了 StringBuilder 來(lái)把生成的字符串逐個(gè)追加起來(lái)。
此外還要注意,如果 Dish 類有一個(gè) toString 方法來(lái)返回菜肴的名稱,那你無(wú)需用提取每一道菜名稱的函數(shù)來(lái)對(duì)原流做映射就能夠得到相同的結(jié)果。
String shortMenu = menu.stream().collect(joining());但該字符串的可讀性并不好。幸好, joining 工廠方法有一個(gè)重載版本可以接受元素之間的分界符,這樣你就可以得到一個(gè)指定分隔符的名稱列表:
public static String joinMenu(List<Dish> menu) {return menu.stream().map(Dish::getName).collect(joining(","));}好了 ,就到這兒吧
總結(jié)
以上是生活随笔為你收集整理的Java 8 - 收集器Collectors_归约和汇总的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java 8 - 收集器Collecto
- 下一篇: Java 8 - 收集器Collecto