乐字节-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,欢迎关注,转载请说明出处和作者。

原文地址:https://www.cnblogs.com/lotbyte/p/10686231.html

时间: 2024-08-19 08:39:03

乐字节-Java8新特性-接口默认方法之Stream流(下)的相关文章

乐字节-Java8新特性之Optional

上一篇小乐带大家了解了Java新特性之Stream,接下来将会继续述说Java新特性之Optional Optional<T>类(java.util.Optional)是一个容器类,代表一个值存在或不存在,原来用null表示一个值不存在,现在Optional可以更好的表达这个概念.并且可以避免空指针异常. 1.of 为非null的值创建一个Optional,如果值为null,则会抛出NullPointerException Optional<Integer> optional =

java8新特性四-默认方法

简介 Java 8 新增了接口的默认方法. 简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法. 我们只需在方法名前面加个 default 关键字即可实现默认方法. 为什么要有这个特性? 首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8 之前的集合框架没有 foreach 方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现.然而,对于已经发布的版本,是没法再给接口添加新方

乐字节-Java8核心特性实战之函数式接口

什么时候可以使用Lambda?通常Lambda表达式是用在函数式接口上使用的.从Java8开始引入了函数式接口,其说明比较简单:函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口. java8引入@FunctionalInterface 注解声明该接口是一个函数式接口. 语法 抽象方法有且仅有一个 接口使用@FunctionalInterface 注解进行标注 接口中可以存在默认方法和静态方法实现 如下形式: /** * 定义函数式

JAVA8新特性——接口定义增强

JAVA9都要出来了,JAVA8新特性都没搞清楚,是不是有点掉队哦~ 接口定义增强 在JDK1.8以前,接口是定义的: 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承接口的抽象方法. 在JDK1.8之前,接口有如下特性: 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错). 接口中

Java8新特性——接口的默认方法和类方法

Java8新增了接口的默认方法和类方法: 以前,接口里的方法要求全部是抽象方法,java8以后允许在接口里定义默认方法和类方法: 不同的是: 默认方法可以通过实现接口的类实例化的对象来调用,而类方法只能在本接口中调用或在实现类中实现 下面是使用实例: 1 public interface MyInter { 2 default void df(){ //声明一个接口的默认方法 3 4 System.out.println("i'am default f"); 5 sf(); //调用本

乐字节Java8核心特性之Optional类

大家好啊,上次小乐给大家介绍了Java8最最重要的一个特性——Stream流,点击可以回顾哦. Optional<T>类(java.util.Optional)是一个容器类,代表一个值存在或不存在,原来用null表示一个值不存在,现在Optional可以更好的表达这个概念.并且可以避免空指针异常. 1.Optinal对象构建&值获取方法 方法 操作描述 <T> Optional<T> of(T value) 为非null的值创建一个Optional,如果值为nu

java8新特性(六):Stream多线程并行数据处理

转:http://blog.csdn.net/sunjin9418/article/details/53143588 将一个顺序执行的流转变成一个并发的流只要调用 parallel()方法 public static long parallelSum(long n){    return Stream.iterate(1L, i -> i +1).limit(n).parallel().reduce(0L,Long::sum); } 并行流就是一个把内容分成多个数据块,并用不不同的线程分别处理每

010-jdk1.8版本新特性二-Optional类,Stream流

1.5.Optional类 1.定义 Optional 类是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象. Optional 是个容器:它可以保存类型T的值,或者仅仅保存null.Optional提供很多有用的方法,这样我们就不用显式进行空值检测. Optional 类的引入很好的解决空指针异常. 2.声明 以下是一个 java.util.Optional<T> 类的声明: public final class Option

浅谈JAVA8引入的接口默认方法

参考 http://blog.csdn.net/wanghao_0206/article/details/52712736 public interface InterfaceTest { public static String oldOldName(){ return "王海"; } default String oldName(){ return "王陆"; } public String myNewName(String name); } public cl