资讯专栏INFORMATION COLUMN

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

20171112 / 3378人阅读

摘要:归约操作计算有效订单总金额有效订单总金额收集数据收集将流转换为其他形式,方法作为终端操作,接收一个接口的实现,用于给中元素做汇总的方法。

接上一篇:《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 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 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());

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 orders= ordersList.stream().filter((order) -> order.getIsValid() == 1).collect(Collectors.toList());
orders.forEach(System.out::println);
// 筛选所有有效订单 并收集订单号 与 订单金额
Map 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> 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>> 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> 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,欢迎关注,转载请说明出处和作者。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77518.html

相关文章

  • 字节-Java8特性Stream(上)

    摘要:需要注意的是很多流操作本身就会返回一个流,所以多个操作可以直接连接起来,如下图这样,操作可以进行链式调用,并且并行流还可以实现数据流并行处理操作。为集合创建并行流。 上一篇文章,小乐给大家介绍了《Java8新特性之方法引用》,下面接下来小乐将会给大家介绍Java8新特性之Stream,称之为流,本篇文章为上半部分。 1、什么是流? Java Se中对于流的操作有输入输出IO流,而Jav...

    dingda 评论0 收藏0
  • 字节-Java8核心特性实战Stream

    摘要:大家好,我是乐字节的小乐。需要注意的是很多流操作本身就会返回一个流,所以多个操作可以直接连接起来,如下图这样,操作可以进行链式调用,并且并行流还可以实现数据流并行处理操作。为集合创建并行流。 大家好,我是乐字节的小乐。说起流,我们会联想到手机、电脑组装流水线,物流仓库商品包装流水线等等,如果把手机 ,电脑,包裹看做最终结果的话,那么加工商品前的各种零部件就可以看做数据源,而中间一系列的...

    wenshi11019 评论0 收藏0
  • 字节-Java8核心特性实战-接口默认方法

    摘要:语法中接口可以包含实现方法,需要使用修饰,此类方法称为默认方法。核心特性接口默认方法就介绍到这里了,后续小乐会继续讲述核心特性。 JAVA8已经发布很久,是自java5(2004年发布)之后Oracle发布的最重要的一个版本。其中包括语言、编译器、库、工具和JVM等诸多方面的新特性,对于国内外互联网公司来说,Java8是以后技术开发的趋势。这里主要讲解在开发中几个核心的新特性。(主要从...

    lbool 评论0 收藏0
  • 字节-Java8核心特性实战函数式接口

    摘要:大家好,上一篇小乐给大家讲述了乐字节核心特性表达式,点击回顾。接下来继续核心特性之函数式接口。感谢大家欣赏小乐带来的核心特性之函数式接口,接下来还会更多核心技术讲解,请关注乐字节如需要视频课程,请搜索乐字节腾讯课堂 大家好,上一篇小乐给大家讲述了《乐字节-Java8核心特性-Lambda表达式》,点击回顾。接下来继续:Java8核心特性之函数式接口。 什么时候可以使用Lambda?通常...

    niceforbear 评论0 收藏0
  • 字节Java8核心特性Optional

    摘要:大家好啊,上次小乐给大家介绍了最最重要的一个特性流,点击可以回顾哦。并且可以避免空指针异常。这种操作对于参数判断提供很大便利,例如参数满足指定条件的后续操作查询操作字符串拼接,常见的处理多请求页面转发处理等操作。 大家好啊,上次小乐给大家介绍了Java8最最重要的一个特性——Stream流,点击可以回顾哦。 Optional类(java.util.Optional)是一个容器类,代表一...

    姘存按 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<