接上一篇:《Java8新特性之stream》,下面繼續接着講Streamjava
常見的流的中間操做,歸爲如下三大類:篩選和切片流操做、元素映射操做、元素排序操做:
segmentfault
例如以訂單數據爲例,在作報表展現時,會根據訂單狀態、用戶信息、支付結果等狀態來分別展現(即過濾和統計展現)ide
定義訂單Order類測試
public class Order { // 訂單id private Integer id; // 訂單用戶id private Integer userId; // 訂單編號 private String orderNo; // 訂單日期 private Date orderDate; // 收貨地址 private String address; // 建立時間 private Date createDate; // 更新時間 private Date updateDate; // 訂單狀態 0-未支付 1-已支付 2-代發貨 3-已發貨 4-已接收 5-已完成 private Integer status; // 是否有效 1-有效訂單 0-無效訂單 private Integer isValid; //訂單總金額 private Double total; /** 此處省略getter/setter方法 */ }
測試this
public static void main(String[] args) { Order order01 = new Order(1,10,"20190301", new Date(),"上海市-浦東區",new Date(),new Date(),4,1,100.0); Order order02 = new Order(2,30,"20190302", new Date(),"北京市四惠區",new Date(),new Date(),1,1,2000.0); Order order03 = new Order(3,20,"20190303", new Date(),"北京市-朝陽區",new Date(),new Date(),4,1,500.0); Order order04 = new Order(4,40,"20190304", new Date(),"北京市-大興區",new Date(),new Date(),4,0,256.0); Order order05 = new Order(5,40,"20190304", new Date(),"上海市-松江區",new Date(),new Date(),4,0,1000.0); List<Order> ordersList= Arrays.asList(order01,order02,order03,order04); // 過濾訂單集合 有效訂單 並打印到控制檯 ordersList.stream().filter((order)->order.getIsValid()==1).forEach(System.out::println); // 過濾訂單集合有效訂單 取前兩條有效訂單 並打印到控制檯 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); // 去除訂單編號重複的無效訂單記錄 此時由於比較的爲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; } // 過濾訂單集合無效訂單 去除訂單號重複記錄 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); // 過濾有效訂單 並分離每一個訂單下收貨地址市區信息 ordersList.stream().map(o->o.getAddress().split("-")).flatMap(Arrays::stream).forEach(System.out::println);
//過濾有效訂單 並根據用戶id 進行排序 ordersList.stream().filter((order)->order.getIsValid()==1) .sorted((o1,o2)->o1.getUserId()-o2.getUserId()).forEach(System.out::println); //或者等價寫法 ordersList.stream().filter((order)->order.getIsValid()==1) .sorted(Comparator.comparingInt(Order::getUserId)).forEach(System.out::println); // 定製排序規則 /*過濾有效訂單 * 定製排序:若是訂單狀態相同 根據訂單建立時間排序 反之根據訂單狀態排序 */ 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);
終止操做會從流的流水線生成結果。其結果是任何不是流的值,好比常見的List、 Integer,甚 至void等結果。spa
對於流的終止操做,分爲如下三類:code
// 篩選全部有效訂單 匹配用戶id =20 的全部訂單 System.out.println("allMatch匹配結果:"+ordersList.stream(). filter((order) -> order.getIsValid() == 1).allMatch((o) -> o.getUserId() == 20)); System.out.println("anyMatch匹配結果:"+ordersList.stream(). filter((order) -> order.getIsValid() == 1).anyMatch((o) -> o.getUserId() == 20)); System.out.println("noneMatch匹配結果:"+ordersList.stream(). filter((order) -> order.getIsValid() == 1).noneMatch((o) -> o.getUserId() == 20)); // 篩選全部有效訂單 返回訂單總數 System.out.println("count結果:"+ordersList.stream(). filter((order) -> order.getIsValid() == 1).count()); // 篩選全部有效訂單 返回金額最大訂單值 Optional<Double> max=ordersList.stream().filter((order) -> order.getIsValid() == 1) .map(Order::getTotal).max(Double::compare); System.out.println("訂單金額最大值:"+max.get()); // 篩選全部有效訂單 返回金額最小訂單值 Optional<Double> min=ordersList.stream().filter((order) -> order.getIsValid() == 1) .map(Order::getTotal).min(Double::compare); System.out.println("訂單金額最小值:"+min.get());
將流中元素反覆結合起來,獲得一個值的操做。 // 歸約操做 計算有效訂單總金額 System.out.println("有效訂單總金額:"+ordersList.stream().filter((order) -> order.getIsValid() == 1).map(Order::getTotal).reduce(Double::sum).get());
6.3.一、收集對象
將流轉換爲其餘形式,coollect 方法做爲終端操做, 接收一個Collector接口的實現,用於給Stream中元素作彙總的方法。最經常使用的方法,把流中全部元素收集到一個 List, Set 或 Collection 中排序
toMap接口
// 收集操做
// 篩選全部有效訂單 並收集訂單列表
List<Order> orders= ordersList.stream().filter((order) -> order.getIsValid() == 1).collect(Collectors.toList());
orders.forEach(System.out::println);
// 篩選全部有效訂單 並收集訂單號 與 訂單金額
Map<String,Double> map=ordersList.stream().filter((order) -> order.getIsValid() == 1).
collect(Collectors.toMap(Order::getOrderNo, Order::getTotal));
// java8 下對map 進行遍歷操做 若是 Map 的 Key 重複了,會報錯
map.forEach((k,v)->{
System.out.println("k:"+k+":v:"+v);
});
6.3.二、彙總
summarizingInt,summarizingLong,summarizingDouble 一樣能夠實現計算總和,平均等操做,好比summarizingInt 結果會返回IntSummaryStatistics 類型 ,而後經過get方法獲取對應彙總值便可
// 彙總操做
//篩選全部有效訂單 返回訂單總數
System.out.println("count結果:"+ordersList.stream().
filter((order) -> order.getIsValid() == 1).collect(Collectors.counting()));
System.out.println("count結果:"+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 有效訂單平均每筆消費金額:"+ordersList.stream().
filter((order) -> order.getIsValid() == 1). filter((order -> order.getUserId()==20)) .collect(Collectors.averagingDouble(Order::getTotal)));
System.out.println("用戶id=20 有效訂單平均每筆消費金額:"+
ordersList.stream(). filter((order) -> order.getIsValid() == 1). filter((order -> order.getUserId()==20)) .mapToDouble(Order::getTotal).average().getAsDouble());
System.out.println("用戶id=20 有效訂單平均每筆消費金額:"+
ordersList.stream(). filter((order) -> order.getIsValid() == 1). filter((order -> order.getUserId()==20)) .collect(Collectors.summarizingDouble(Order::getTotal)).getAverage());
// 篩選全部有效訂單 並計算訂單總金額
System.out.println("訂單總金額:"+ordersList.stream().filter((order) -> order.getIsValid() == 1)
.collect(Collectors.summingDouble(Order::getTotal)));
// 篩選全部有效訂單 並計算最小訂單金額
System.out.println("最小訂單金額:"+ordersList.stream().filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal).collect(Collectors.minBy(Double::compare)));
// 篩選全部有效訂單 並計算最大訂單金額
System.out.println("最大訂單金額:"+ordersList.stream().filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal).collect(Collectors.maxBy(Double::compare)));
6.3.三、最值
maxBy,minBy 兩個方法,須要一個 Comparator 接口做爲參數,實現最大 最小值獲取操做 // 取最會 // 篩選全部有效訂單 並計算最小訂單金額 System.out.println("最小訂單金額:"+ordersList.stream().filter((order) -> order.getIsValid() == 1) .map(Order::getTotal).collect(Collectors.minBy(Double::compare))); // 篩選全部有效訂單 並計算最大訂單金額 System.out.println("最大訂單金額:"+ordersList.stream().filter((order) -> order.getIsValid() == 1) .map(Order::getTotal).collect(Collectors.maxBy(Double::compare)));
6.3.四、分組
groupingBy 用於將數據分組,最終返回一個 Map 類型
groupingBy 能夠接受一個第二參數實現多級分組
// 分組-根據有效訂單支付狀態進行分組操做 Map<Integer,List<Order>> g01=ordersList.stream().filter((order) -> order.getIsValid() == 1) .collect(Collectors.groupingBy(Order::getStatus)); g01.forEach((status,order)->{ System.out.println("----------------"); System.out.println("訂單狀態:"+status); order.forEach(System.out::println); }); // 分組-查詢有效訂單 根據用戶id 和 支付狀態進行分組 Map<Integer,Map<String,List<Order>>> 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 "待發貨"; }else if (o.getStatus()==3){ return "已發貨"; }else if (o.getStatus()==4){ return "已接收"; } else{ return "已完成"; } }))); g02.forEach((userId,m)->{ System.out.println("用戶id:"+userId+"-->有效訂單以下:"); m.forEach((status,os)->{ System.out.println("狀態:"+status+"---訂單列表以下:"); os.forEach(System.out::println); }); System.out.println("-----------------------"); });
6.3.五、partitioningBy 分區
分區與分組的區別在於,分區是按照 true 和 false 來分的,所以partitioningBy 接受的參數的 lambda 也是 T -> boolean // 分區操做 篩選訂單金額>1000 的有效訂單 Map<Boolean,List<Order>> g03= ordersList.stream().filter((order) -> order.getIsValid() == 1) .collect(Collectors.partitioningBy((o)->o.getTotal()>1000)); g03.forEach((b,os)->{ System.out.println("分區結果:"+b+"--列表結果:"); os.forEach(System.out::println); }); // 拼接操做 篩選有效訂單 並進行拼接 String orderStr=ordersList.stream().filter((order) -> order.getIsValid() == 1).map(Order::getOrderNo) .collect(Collectors.joining(",")); System.out.println(orderStr);
樂字節-Java新特性之stream流就介紹到這裏了,接下來小樂還會接着給你們講解Java8新特性之Optional,歡迎關注,轉載請說明出處和做者。