摘要:歸約操作計(jì)算有效訂單總金額有效訂單總金額收集數(shù)據(jù)收集將流轉(zhuǎn)換為其他形式,方法作為終端操作,接收一個(gè)接口的實(shí)現(xiàn),用于給中元素做匯總的方法。
接上一篇:《Java8新特性之stream》,下面繼續(xù)接著講Stream
5、流的中間操作常見的流的中間操作,歸為以下三大類:篩選和切片流操作、元素映射操作、元素排序操作:
例如以訂單數(shù)據(jù)為例,在做報(bào)表展示時(shí),會(huì)根據(jù)訂單狀態(tài)、用戶信息、支付結(jié)果等狀態(tài)來分別展示(即過濾和統(tǒng)計(jì)展示)
定義訂單Order類
public class Order { // 訂單id private Integer id; // 訂單用戶id private Integer userId; // 訂單編號 private String orderNo; // 訂單日期 private Date orderDate; // 收貨地址 private String address; // 創(chuàng)建時(shí)間 private Date createDate; // 更新時(shí)間 private Date updateDate; // 訂單狀態(tài) 0-未支付 1-已支付 2-代發(fā)貨 3-已發(fā)貨 4-已接收 5-已完成 private Integer status; // 是否有效 1-有效訂單 0-無效訂單 private Integer isValid; //訂單總金額 private Double total; /** 此處省略getter/setter方法 */ }
測試
public static void main(String[] args) { Order order01 = new Order(1,10,"20190301", new Date(),"上海市-浦東區(qū)",new Date(),new Date(),4,1,100.0); Order order02 = new Order(2,30,"20190302", new Date(),"北京市四惠區(qū)",new Date(),new Date(),1,1,2000.0); Order order03 = new Order(3,20,"20190303", new Date(),"北京市-朝陽區(qū)",new Date(),new Date(),4,1,500.0); Order order04 = new Order(4,40,"20190304", new Date(),"北京市-大興區(qū)",new Date(),new Date(),4,0,256.0); Order order05 = new Order(5,40,"20190304", new Date(),"上海市-松江區(qū)",new Date(),new Date(),4,0,1000.0); List5.2、映射ordersList= Arrays.asList(order01,order02,order03,order04); // 過濾訂單集合 有效訂單 并打印到控制臺(tái) ordersList.stream().filter((order)->order.getIsValid()==1).forEach(System.out::println); // 過濾訂單集合有效訂單 取前兩條有效訂單 并打印到控制臺(tái) ordersList.stream().filter((order)->order.getIsValid()==1).limit(2).forEach(System.out::println); } // 過濾訂單集合有效訂單 取最后一條記錄 ordersList.stream().filter((order)->order.getIsValid()==1) .skip(ordersList.size()-2).forEach(System.out::println); // 去除訂單編號重復(fù)的無效訂單記錄 此時(shí)因?yàn)楸容^的為Object Order對象需要重寫HashCode 與Equals 方法 /** * 重寫 equals 方法 * @param obj * @return */ @Override public boolean equals(Object obj) { boolean flag = false; if (obj == null) { return flag; } Order order = (Order) obj; if (this == order) { return true; } else { return (this.orderNo.equals(order.orderNo)); } } /** * 重寫hashcode方法 * @return */ @Override public int hashCode() { int hashno = 7; hashno = 13 * hashno + (orderNo == null ? 0 : orderNo.hashCode()); return hashno; } // 過濾訂單集合無效訂單 去除訂單號重復(fù)記錄 ordersList.stream().filter((order)->order.getIsValid()==0).distinct().forEach(System.out::println);
//過濾訂單集合有效訂單 獲取所有訂單訂單編號 ordersList.stream().filter((order)->order.getIsValid()==1).map((order)->order.getOrderNo()).forEach(System.out::println); // 過濾有效訂單 并分離每個(gè)訂單下收貨地址市區(qū)信息 ordersList.stream().map(o->o.getAddress().split("-")).flatMap(Arrays::stream).forEach(System.out::println);5.3、排序
//過濾有效訂單 并根據(jù)用戶id 進(jìn)行排序 ordersList.stream().filter((order)->order.getIsValid()==1) .sorted((o1,o2)->o1.getUserId()-o2.getUserId()).forEach(System.out::println); //或者等價(jià)寫法 ordersList.stream().filter((order)->order.getIsValid()==1) .sorted(Comparator.comparingInt(Order::getUserId)).forEach(System.out::println); // 定制排序規(guī)則 /*過濾有效訂單 * 定制排序:如果訂單狀態(tài)相同 根據(jù)訂單創(chuàng)建時(shí)間排序 反之根據(jù)訂單狀態(tài)排序 */ ordersList.stream().filter((order)->order.getIsValid()==1).sorted((o1,o2)->{ if(o1.getStatus().equals(o2.getStatus())){ return o1.getCreateDate().compareTo(o2.getCreateDate()); }else{ return o1.getStatus().compareTo(o2.getStatus()); }}).forEach(System.out::println);6、流的終止操作
終止操作會(huì)從流的流水線生成結(jié)果。其結(jié)果是任何不是流的值,比如常見的List、 Integer,甚 至void等結(jié)果。
對于流的終止操作,分為以下三類:
6.1、查找與匹配// 篩選所有有效訂單 匹配用戶id =20 的所有訂單 System.out.println("allMatch匹配結(jié)果:"+ordersList.stream(). filter((order) -> order.getIsValid() == 1).allMatch((o) -> o.getUserId() == 20)); System.out.println("anyMatch匹配結(jié)果:"+ordersList.stream(). filter((order) -> order.getIsValid() == 1).anyMatch((o) -> o.getUserId() == 20)); System.out.println("noneMatch匹配結(jié)果:"+ordersList.stream(). filter((order) -> order.getIsValid() == 1).noneMatch((o) -> o.getUserId() == 20)); // 篩選所有有效訂單 返回訂單總數(shù) System.out.println("count結(jié)果:"+ordersList.stream(). filter((order) -> order.getIsValid() == 1).count()); // 篩選所有有效訂單 返回金額最大訂單值 Optional6.2、歸約max=ordersList.stream().filter((order) -> order.getIsValid() == 1) .map(Order::getTotal).max(Double::compare); System.out.println("訂單金額最大值:"+max.get()); // 篩選所有有效訂單 返回金額最小訂單值 Optional min=ordersList.stream().filter((order) -> order.getIsValid() == 1) .map(Order::getTotal).min(Double::compare); System.out.println("訂單金額最小值:"+min.get());
將流中元素反復(fù)結(jié)合起來,得到一個(gè)值的操作。 // 歸約操作 計(jì)算有效訂單總金額 System.out.println("有效訂單總金額:"+ordersList.stream().filter((order) -> order.getIsValid() == 1).map(Order::getTotal).reduce(Double::sum).get());6.3、Collector收集數(shù)據(jù)
6.3.1、收集
將流轉(zhuǎn)換為其他形式,coollect 方法作為終端操作, 接收一個(gè)Collector接口的實(shí)現(xiàn),用于給Stream中元素做匯總的方法。最常用的方法,把流中所有元素收集到一個(gè) List, Set 或 Collection 中
toList
toSet
toCollection
toMap
// 收集操作
// 篩選所有有效訂單 并收集訂單列表
List
orders.forEach(System.out::println);
// 篩選所有有效訂單 并收集訂單號 與 訂單金額
Map
collect(Collectors.toMap(Order::getOrderNo, Order::getTotal));
// java8 下對map 進(jìn)行遍歷操作 如果 Map 的 Key 重復(fù)了,會(huì)報(bào)錯(cuò)
map.forEach((k,v)->{
System.out.println("k:"+k+":v:"+v);
});
6.3.2、匯總
countintg():用于計(jì)算總和
count():用于計(jì)算總和(推薦使用,寫法更簡潔)
summingInt() ,summingLong(),summingDouble():用于計(jì)算總和
averagingInt(),averagingLong(),averagingDouble()用于平均
summarizingInt,summarizingLong,summarizingDouble 同樣可以實(shí)現(xiàn)計(jì)算總和,平均等操作,比如summarizingInt 結(jié)果會(huì)返回IntSummaryStatistics 類型 ,然后通過get方法獲取對應(yīng)匯總值即可
// 匯總操作
//篩選所有有效訂單 返回訂單總數(shù)
System.out.println("count結(jié)果:"+ordersList.stream().
filter((order) -> order.getIsValid() == 1).collect(Collectors.counting()));
System.out.println("count結(jié)果:"+ordersList.stream().
filter((order) -> order.getIsValid() == 1).count());
// 返回訂單總金額
System.out.println("訂單總金額:"+ordersList.stream().
filter((order) -> order.getIsValid() == 1).collect(Collectors.summarizingDouble(Order::getTotal)));
System.out.println("訂單總金額:"+ordersList.stream().
filter((order) -> order.getIsValid() == 1).mapToDouble(Order::getTotal).sum());
System.out.println("訂單總金額:"+ordersList.stream().
filter((order) -> order.getIsValid() == 1).map(Order::getTotal).reduce(Double::sum).get());
// 返回 用戶id=20 有效訂單平均每筆消息金額
System.out.println("用戶id=20 有效訂單平均每筆消費(fèi)金額:"+ordersList.stream().
filter((order) -> order.getIsValid() == 1). filter((order -> order.getUserId()==20)) .collect(Collectors.averagingDouble(Order::getTotal)));
System.out.println("用戶id=20 有效訂單平均每筆消費(fèi)金額:"+
ordersList.stream(). filter((order) -> order.getIsValid() == 1). filter((order -> order.getUserId()==20)) .mapToDouble(Order::getTotal).average().getAsDouble());
System.out.println("用戶id=20 有效訂單平均每筆消費(fèi)金額:"+
ordersList.stream(). filter((order) -> order.getIsValid() == 1). filter((order -> order.getUserId()==20)) .collect(Collectors.summarizingDouble(Order::getTotal)).getAverage());
// 篩選所有有效訂單 并計(jì)算訂單總金額
System.out.println("訂單總金額:"+ordersList.stream().filter((order) -> order.getIsValid() == 1)
.collect(Collectors.summingDouble(Order::getTotal)));
// 篩選所有有效訂單 并計(jì)算最小訂單金額
System.out.println("最小訂單金額:"+ordersList.stream().filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal).collect(Collectors.minBy(Double::compare)));
// 篩選所有有效訂單 并計(jì)算最大訂單金額
System.out.println("最大訂單金額:"+ordersList.stream().filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal).collect(Collectors.maxBy(Double::compare)));
6.3.3、最值
maxBy,minBy 兩個(gè)方法,需要一個(gè) Comparator 接口作為參數(shù),實(shí)現(xiàn)最大 最小值獲取操作 // 取最會(huì) // 篩選所有有效訂單 并計(jì)算最小訂單金額 System.out.println("最小訂單金額:"+ordersList.stream().filter((order) -> order.getIsValid() == 1) .map(Order::getTotal).collect(Collectors.minBy(Double::compare))); // 篩選所有有效訂單 并計(jì)算最大訂單金額 System.out.println("最大訂單金額:"+ordersList.stream().filter((order) -> order.getIsValid() == 1) .map(Order::getTotal).collect(Collectors.maxBy(Double::compare)));
6.3.4、分組
groupingBy 用于將數(shù)據(jù)分組,最終返回一個(gè) Map 類型
groupingBy 可以接受一個(gè)第二參數(shù)實(shí)現(xiàn)多級分組
// 分組-根據(jù)有效訂單支付狀態(tài)進(jìn)行分組操作 Map> g01=ordersList.stream().filter((order) -> order.getIsValid() == 1) .collect(Collectors.groupingBy(Order::getStatus)); g01.forEach((status,order)->{ System.out.println("----------------"); System.out.println("訂單狀態(tài):"+status); order.forEach(System.out::println); }); // 分組-查詢有效訂單 根據(jù)用戶id 和 支付狀態(tài)進(jìn)行分組 Map >> g02= ordersList.stream().filter((order) -> order.getIsValid() == 1) .collect(Collectors.groupingBy(Order::getUserId,Collectors.groupingBy((o)->{ if(o.getStatus()==0){ return "未支付"; }else if (o.getStatus()==1){ return "已支付"; }else if (o.getStatus()==2){ return "待發(fā)貨"; }else if (o.getStatus()==3){ return "已發(fā)貨"; }else if (o.getStatus()==4){ return "已接收"; } else{ return "已完成"; } }))); g02.forEach((userId,m)->{ System.out.println("用戶id:"+userId+"-->有效訂單如下:"); m.forEach((status,os)->{ System.out.println("狀態(tài):"+status+"---訂單列表如下:"); os.forEach(System.out::println); }); System.out.println("-----------------------"); });
6.3.5、partitioningBy 分區(qū)
分區(qū)與分組的區(qū)別在于,分區(qū)是按照 true 和 false 來分的,因此partitioningBy 接受的參數(shù)的 lambda 也是?T -> boolean // 分區(qū)操作 篩選訂單金額>1000 的有效訂單 Map> g03= ordersList.stream().filter((order) -> order.getIsValid() == 1) .collect(Collectors.partitioningBy((o)->o.getTotal()>1000)); g03.forEach((b,os)->{ System.out.println("分區(qū)結(jié)果:"+b+"--列表結(jié)果:"); os.forEach(System.out::println); }); // 拼接操作 篩選有效訂單 并進(jìn)行拼接 String orderStr=ordersList.stream().filter((order) -> order.getIsValid() == 1).map(Order::getOrderNo) .collect(Collectors.joining(",")); System.out.println(orderStr);
樂字節(jié)-Java新特性之stream流就介紹到這里了,接下來小樂還會(huì)接著給大家講解Java8新特性之Optional,歡迎關(guān)注,轉(zhuǎn)載請說明出處和作者。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/77518.html
摘要:需要注意的是很多流操作本身就會(huì)返回一個(gè)流,所以多個(gè)操作可以直接連接起來,如下圖這樣,操作可以進(jìn)行鏈?zhǔn)秸{(diào)用,并且并行流還可以實(shí)現(xiàn)數(shù)據(jù)流并行處理操作。為集合創(chuàng)建并行流。 上一篇文章,小樂給大家介紹了《Java8新特性之方法引用》,下面接下來小樂將會(huì)給大家介紹Java8新特性之Stream,稱之為流,本篇文章為上半部分。 1、什么是流? Java Se中對于流的操作有輸入輸出IO流,而Jav...
摘要:大家好,我是樂字節(jié)的小樂。需要注意的是很多流操作本身就會(huì)返回一個(gè)流,所以多個(gè)操作可以直接連接起來,如下圖這樣,操作可以進(jìn)行鏈?zhǔn)秸{(diào)用,并且并行流還可以實(shí)現(xiàn)數(shù)據(jù)流并行處理操作。為集合創(chuàng)建并行流。 大家好,我是樂字節(jié)的小樂。說起流,我們會(huì)聯(lián)想到手機(jī)、電腦組裝流水線,物流倉庫商品包裝流水線等等,如果把手機(jī) ,電腦,包裹看做最終結(jié)果的話,那么加工商品前的各種零部件就可以看做數(shù)據(jù)源,而中間一系列的...
摘要:語法中接口可以包含實(shí)現(xiàn)方法,需要使用修飾,此類方法稱為默認(rèn)方法。核心特性接口默認(rèn)方法就介紹到這里了,后續(xù)小樂會(huì)繼續(xù)講述核心特性。 JAVA8已經(jīng)發(fā)布很久,是自java5(2004年發(fā)布)之后Oracle發(fā)布的最重要的一個(gè)版本。其中包括語言、編譯器、庫、工具和JVM等諸多方面的新特性,對于國內(nèi)外互聯(lián)網(wǎng)公司來說,Java8是以后技術(shù)開發(fā)的趨勢。這里主要講解在開發(fā)中幾個(gè)核心的新特性。(主要從...
摘要:大家好,上一篇小樂給大家講述了樂字節(jié)核心特性表達(dá)式,點(diǎn)擊回顧。接下來繼續(xù)核心特性之函數(shù)式接口。感謝大家欣賞小樂帶來的核心特性之函數(shù)式接口,接下來還會(huì)更多核心技術(shù)講解,請關(guān)注樂字節(jié)如需要視頻課程,請搜索樂字節(jié)騰訊課堂 大家好,上一篇小樂給大家講述了《樂字節(jié)-Java8核心特性-Lambda表達(dá)式》,點(diǎn)擊回顧。接下來繼續(xù):Java8核心特性之函數(shù)式接口。 什么時(shí)候可以使用Lambda?通常...
摘要:大家好啊,上次小樂給大家介紹了最最重要的一個(gè)特性流,點(diǎn)擊可以回顧哦。并且可以避免空指針異常。這種操作對于參數(shù)判斷提供很大便利,例如參數(shù)滿足指定條件的后續(xù)操作查詢操作字符串拼接,常見的處理多請求頁面轉(zhuǎn)發(fā)處理等操作。 大家好啊,上次小樂給大家介紹了Java8最最重要的一個(gè)特性——Stream流,點(diǎn)擊可以回顧哦。 Optional類(java.util.Optional)是一個(gè)容器類,代表一...
閱讀 4736·2021-11-18 13:23
閱讀 910·2021-09-22 15:24
閱讀 1933·2021-09-06 15:00
閱讀 2638·2021-09-03 10:30
閱讀 1292·2021-09-02 15:15
閱讀 2083·2019-08-30 15:54
閱讀 3041·2019-08-30 15:44
閱讀 1462·2019-08-29 15:12