接上一篇:《Java8新特性之stream》,下面继续接着讲Stream
常见的流的中间操作,归为以下三大类:筛选和切片流操作、元素映射操作、元素排序操作:
例如以订单数据为例,在做报表展示时,会根据订单状态、用户信息、支付结果等状态来分别展示(即过滤和统计展示)
定义订单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方法 */ }
测试
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等结果。
对于流的终止操作,分为以下三类:
// 筛选所有有效订单 匹配用户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());
将流转换为其他形式,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);
});
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)));
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)));
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("-----------------------"); });
分区与分组的区别在于,分区是按照 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,欢迎关注,转载请说明出处和作者。