乐字节-Java8新特性-接口默认方法之Stream流(下)
接上一篇:《java8新特性之stream》,下面继续接着讲stream
5、流的中间操作
常见的流的中间操作,归为以下三大类:筛选和切片流操作、元素映射操作、元素排序操作:
操作 | 描述 |
---|---|
筛选和切片 | filter(t -> boolean):保留 boolean 为 true 的元素 limit(long n):返回前 n 个元素 skip(long n):去除前 n 个元素 distinct():去除重复元素,这个方法是通过类的 equals 方法来判断两个元素是否相等的 |
映射 | map(t -> r):将流中的每一个元素 t 映射为 r(类似类型转换) flatmap(t -> stream<r>): 将流中的每一个元素 t 映射为一个流,再把每一个流连接成为一个流 |
排序 | sorted() / sorted((t, t) -> int):如果流中的元素的类实现了 comparable 接口,即有自己的排序规则,那么可以直接调用 sorted() 方法对元素进行排序,如 stream<integer> |
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等结果。 对于流的终止操作,分为以下三类:
操作 | 描述 |
---|---|
查找与匹配 | allmatch:检查是否匹配所有元素 anymatch(t -> boolean): 流中是否有一个元素匹配给定的 t -> boolean 条件 nonematch(t -> boolean): 流中是否没有元素匹配给定的 t -> boolean 条件 findany():找到其中一个元素 (使用 stream() 时找到的是第一个元素;使用 parallelstream() 并行时找到的是其中一个元素) findfirst():找到第一个元素 max():返回流中最大值 min():返回流中最小值 count():返回流中元素的总个数 |
归约: 将流中元素反复结合起来,得到一个值 | reduce((t, t) -> t) 和 reduce(t, (t, t) -> t): 用于组合流中的元素,如求和,求积,求最大值等 |
收集: 将流转换为其他形式,接收一个collertor接口的实现,用于给stream中元素做汇总的方法 | collect() |
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,欢迎关注,转载请说明出处和作者。
上一篇: 17岁的宫女因孕封妃,久久没有生下来就被赶到宫廷走道上冻死
下一篇: 我从来没有反对过