乐字节-Java8新特性之Stream流(下)

9次阅读

共计 8650 个字符,预计需要花费 22 分钟才能阅读完成。

接上一篇:《Java8 新特性之 stream》,下面继续接着讲 Stream
5、流的中间操作
常见的流的中间操作,归为以下三大类:筛选和切片流操作、元素映射操作、元素排序操作:
5.1、筛选和切片
例如以订单数据为例,在做报表展示时,会根据订单状态、用户信息、支付结果等状态来分别展示(即过滤和统计展示)
定义订单 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);

5.2、映射
// 过滤订单集合有效订单 获取所有订单订单编号
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);

5.3、排序
// 过滤有效订单 并根据用户 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);

6、流的终止操作
终止操作会从流的流水线生成结果。其结果是任何不是流的值,比如常见的 List、Integer,甚 至 void 等结果。
对于流的终止操作,分为以下三类:

6.1、查找与匹配
// 筛选所有有效订单 匹配用户 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());

6.2、归约
将流中元素反复结合起来,得到一个值的操作。

// 归约操作 计算有效订单总金额
System.out.println(“ 有效订单总金额:”+ordersList.stream().filter((order) -> order.getIsValid() == 1).map(Order::getTotal).reduce(Double::sum).get());

6.3、Collector 收集数据
6.3.1、收集
将流转换为其他形式,coollect 方法作为终端操作,接收一个 Collector 接口的实现,用于给 Stream 中元素做汇总的方法。最常用的方法,把流中所有元素收集到一个 List, Set 或 Collection 中

toList
toSet
toCollection

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.2、汇总

countintg(): 用于计算总和
count(): 用于计算总和(推荐使用,写法更简洁)
summingInt(),summingLong(),summingDouble(): 用于计算总和
averagingInt(),averagingLong(),averagingDouble() 用于平均

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.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.4、分组
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.5、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,欢迎关注,转载请说明出处和作者。

正文完
 0