zoukankan      html  css  js  c++  java
  • 乐字节-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,欢迎关注,转载请说明出处和作者。

     

  • 相关阅读:
    获取数据
    织梦入门2-采集1
    织梦入门1-修改
    ThinkPHP角色控制时的错误
    sublime 3打开中文乱码问题
    php抓取远程数据显示在下拉列表中
    php curl的正确使用方法
    Linux 在文件夹的所有文件中查找某字符
    webman 关于数据库性能
    虚拟机centos安装方法
  • 原文地址:https://www.cnblogs.com/lotbyte/p/10686231.html
Copyright © 2011-2022 走看看