Java8的StreamAPI,啊!真香~

277 阅读3分钟

「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战

StreamAPI

Stream它专注于对数据源进行各种高效的聚合操作(aggregate operation)和大批量数据操作 (bulk data operation)。Stream API将处理的数据源看做一种Stream(流),Stream(流)在Pipeline(管道)中传输和运算,支持的运算包含筛选、排序、聚合等,当到达终点后便得到最终的处理结果。

概述:Stream关注的是对数据的运算,与CPU打交道。

  • 集合关注的是数据的存储,与内存打交道

    • Stream自己不会存储元素。
    • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
    • Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
    • Stream流可创建串行和并行两种模式。
  • Stream执行流程

    • Stream的实例化
    • 一系列的中间操作(过滤、映射、...)
    • 终止操作
  • 说明:

    • 一个中间操作链,对数据源的数据进行处理。
    • 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。

简单使用

1、Stream流创建方式

方式一:通过集合

    List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
    
    //default Stream<E> stream():返回一个顺序流
    Stream<Integer> stream = list.stream();
    
    //default Stream<E> parallelStream():返回一个并行流
    Stream<Integer> parallelStream = list.parallelStream();

方式二:通过数组

    int[] arr=new int[]{1,2,3,4,5};
    //调用Arrays类的static<T> Stream<T> stream(T[] array):返回一个流
    IntStream stream = Arrays.stream(arr);

方式三:通过Stream的of()方法

    Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);

方式四:创建Stream无限流

//迭代
//public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//遍历输出前10个偶数
Stream.iterate(0,t-> t+2).limit(10).forEach(System.out::println);

2、Stream流的中间操作

搞点数据:

class BoyData{
    public static List<Boy> getBoy(){
        List<Boy> list=new ArrayList<>();
        list.add(new Boy("aa",20));
        list.add(new Boy("bb",30));
        list.add(new Boy("cc",25));
        list.add(new Boy("dd",23));
        list.add(new Boy("ee",28));
        list.add(new Boy("ee",28));
        list.add(new Boy("ee",28));
        return list;

    }
}

看下面操作---

2.1、筛选与切片

  • filter(Predicate p):接收Lambda ,从流中排除某些元素。
    List<Boy> boyList = BoyData.getBoy();
    //创建Stream流,以便后续操作。
    Stream<Boy> boyStream = boyList.stream();
    
    //排除年龄小于25的boy,并输出。
    boyStream.filter(b->b.getAge()>25).forEach(System.out::println);
  • limit(n):截断流,使其元素不超过给定数量。
    //截取前2条数据并输出。
    boyStream.limit(2).forEach(System.out::println);

  • skip(n):跳过元素,返回一个扔掉了前n个元素的年。若流中元素不足n个,则返回一个空流。
    //跳过前2条数据并输出
    boyStream.skip(2).forEach(System.out::println);
  • distinct():筛选,通过流所生成元素的 hashCode()和equals()去除重复元素。
    //去除数据集合中的重复元素,并输出
    boyStream.distinct().forEach(System.out::println);

重点:此时需要重写javaBean中的equals和hashcode方法,否则该方法失效。

重写代码:

@Override
public int hashCode() {
    int result;
    long temp;
    result = 1;
    result = 31 * result + (name != null ? name.hashCode() : 0);
    result = 31 * result + age;
    temp = Double.doubleToLongBits(age);
    result = 31 * result + (int) (temp ^ (temp >>> 32));
    return result;
}

@Override
public boolean equals(Object o) {
    if(this==o){
        return true;
    }
    if(o == null||getClass()!=o.getClass()){
        return  false;
    }

    Boy boy = (Boy) o;

    if(age !=boy.age){
        return false;
    }

    return name !=null?name.equals(boy.name):boy.name ==null;
}

2.2、排序

    //自然排序
    List<Integer> integers = Arrays.asList(18, 43, 66, 22, 4, 97, 12);
    integers.stream().sorted().forEach(System.out::println);
    //根据年龄从小到大(定制排序)
    boyStream.sorted((b1,b2)->Integer.compare(b1.getAge(),b2.getAge()))
    .forEach(System.out::println);

3、Stream流的终止操作

真香操作:

  • allMatch(Predicate p):检查是否匹配所有元素。
    • 查看所有人年龄是否都大于20

        boolean allMatch = boyStream.allMatch(b -> b.getAge() > 19);
        System.out.println("所有人年龄是否都大于19:"+(allMatch==true?"是":"不是"));
      
    • 结果:

      image.png

  • anyMatch(Predicate p):检查是否至少匹配一个元素。
  • noneMatch(Predicate p):检查是否没有匹配的元素。
  • findFirst():返回第一个元素。
    • 返回第一个boy

        Optional<Boy> first = boyStream.findFirst();
        System.out.println(first);
      
    • 结果:

      image.png

  • findAny():随机返回当前流中的任意一个元素。
  • count():返回流中元素的总个数。
    • 显示总共有几个boy

        long count = boyStream.count();
        System.out.println(count);
      
    • 结果:

      image.png

  • max(Comparator c):返回流中最大值。
    • 输出最大的年龄值

        Optional<Integer> maxBoy = boyStream.map(boy -> boy.getAge()).max((b1,b2)->b1.compareTo(b2));
        System.out.println(maxBoy.get());
      
    • 结果:

      image.png

  • min(Comparator c):返回流中最小值。
  • forEach(Consumer c):内部迭代。
    • 输出所有boy

        boyStream.forEach(System.out::println);
      
    • 结果:

      image.png

  • 规约
    • reduce()——可以将流中元素反复结合起来,得到一个值并返回。

    • 计算所有boy的年龄总和

          Optional<Integer> sumAge = boyStream.map(boy -> boy.getAge()).reduce((b1, b2) -> b1 + b2);
          System.out.println(sumAge.get());
      
    • 结果

      image.png

  • 收集
    • 查找年龄小于26的boy,并存储在一个集合中返回。

        List<Boy> boyList1 = boyStream.filter(boy -> boy.getAge() < 26)
        .collect(Collectors.toList());
        boyList1.forEach(System.out::println);
      
    • 结果:

      image.png

谢谢观看,至此结束!希望它能成为你的新宠~