博客地址(点击即可访问)github源码地址
Lamda表达式https://github.com/zz1044063894/lambda
函数式接口https://github.com/zz1044063894/methodInterface
方法引用和构造器引用https://github.com/zz1044063894/qoute
Stream APIhttps://github.com/zz1044063894/StreamAPI
接口中的默认方法与静态方法https://github.com/zz1044063894/static-default-method
新时间日期APIhttps://github.com/zz1044063894/newDateTimeAPI

概述

  • Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

  • Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

  • Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

  • 这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

  • 元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

什么是Stream流

Stream(流)是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
  • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

集合讲的是数据,流讲的是的计算.
注意:
- Stream不会自己储存元素
- 不会改变源对象。会产生一个新的持有结果的Stream
- Stream操作是延迟执行的,也就是说他们等到需要结果的时候才执行

流的操作的三个步骤

创建流

一个数据源(如:集合,数组),获取一个流

在 Java 8 中, 集合接口有两个方法来生成流:

  • stream() − 为集合创建串行流。

  • parallelStream() − 为集合创建并行流。

 /**
     * 创建流
     */
    @Test
    public void createStream() {

        /**
         * 1。
         * 用collection集合的stream() − 为集合创建串行流
         *
         * 或者用collection集合的parallelStream() − 为集合创建并行流。
         */
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();


        /**
         * 2。通过Arrays中的静态方法stream()获取数组流
         *  这里因为不想创建对象了,就使用了一个系统对象夫类Object
         */

        Object[] objects = new Object[10];
        Stream<Object> stream2 = Arrays.stream(objects);
        /**
         * 3。通过Stream类中的静态方法of
         */
        Stream<String> stream3 = Stream.of("aa", "bb", "cc");

        /**
         * 4.创建无限流
         */
        //迭代产生无限流
        Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
        //查看结果,用了中间流
        stream4.limit(10)
                .forEach(System.out::println);
        //生成无限流
        Stream.generate(() -> Math.random())
                .limit(5)
                .forEach(System.out::println);
    }

中间操作

一个中间操作链,对数据源的数据进行处理
多个中间操作可以连接起来作为一个流水线,除非流水线上中断中间操作,否则中间操作不会执行任何处理,只会在终端操作的时候一次处理。称为“惰性求值”。

筛选和切片

  • filter 用于通过设置的条件过滤出元素,接受参数是Lambda表达式,类似于SQL语句的where条件内容
/**
     * 筛选与切片
     */
    @Test
    public void test(){
        List<User> users = Arrays.asList(
                new User("张三",24),
                new User("李四",15),
                new User("王五",16),
                new User("赵六",27),
                new User("田七",18)
        );
        Stream<User> stream = users.stream()
                .filter(e->{
                    System.out.println("Stream API中间操作");
                    return e.age>=18;
                });
        //终止操作
        stream.forEach(System.out::println);
    }
    class User{
        String name;
        int age;

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }

运行结果:在这里插入图片描述
可以看出,每次比较条件是都会运行,输出中间操作是为了证明如果没有终止操作,那么系统就不会运行中间操作,只是将操作记录下来,并没有执行

  • limit 用于获取指定数量的流 类似于SQL语句的 limit
  • skip(n) 跳过元素 类似于SQL语句的offset
  • distinct 通过元素的hashcode和equals判断是否想等,相等的内容只返回一个,类似于SQL关键字distinct
  • sorted 用于对流进行排序,类似与SQL语句的order by

映射

  • map 用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:
 /**
     * 映射
     */
    @Test
    public void test1() {
        List<String> list = Arrays.asList("aaa", "bbbb", "ccc");
        list.stream()
                .map((x) -> x.toUpperCase())
                .forEach(System.out::println);
    }

运行结果:
在这里插入图片描述
这里map操作字符串,将字符串转换为大写,然后赋给新流,笔者没有直接拿新流接收,直接输出流。

  • flatMap 类似于map操作,但是将可能存在的多个流转换成一个流存储,可以参考对象里包含对象,map如果操作的返回值是一个对象,map本身也会有一个对象来存储map的结果,这就操作了对象中包含对象,也就是流中有流,flatmap会取到对象中的元素,然后把这些元素构成一个新的流。(也可以类似与list的add(Objcet)和addAll(collection) add是将object作为一个新元素放进去,而addAll是把集合的元素拆分出来依次放进去)

排序

  • sorted 用于对流进行排序,默认按照compareTo方法排序,也可以自己定义排序方式。
/**
     * 排序
     */
    @Test
    public void test2() {
        List<String> list = Arrays.asList("ddd", "aaa", "bbbb", "ccc");
        System.out.println("---------自然排序");
        list.stream()
                .sorted()
                .forEach(System.out::println);

        System.out.println("---------zidingyi排序");
        list.stream()
                .sorted((a,b)->{
                    if(a.equals(b)){
                        return a.compareTo(b);
                    }else {
                        return -a.compareTo(b);
                    }
                })
                .forEach(System.out::println);

    }

结果:
在这里插入图片描述
笔者为了省事,就直接倒序排了一下,只要在sort内部写好你要排序的方法,就可以自己实现排序规则了。

查找与匹配

  • allMatch-检查是否匹配所有元素

  • anyMatch-检查是否至少匹配- - -个元素noneMatch-检 查是否没有匹配所有元素findFirst-返 回第一个元素

  • findAny-返回当前流中的任意元素count-返 回流中元素的总个数

  • max-返回流中最大值

  • min-返 回流中最小值

/**
     * 查找与匹配
     */
    @Test
    public void test3(){
        List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);

        IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();

        System.out.println("列表中最大的数 : " + stats.getMax());
        System.out.println("列表中最小的数 : " + stats.getMin());
        System.out.println("所有数之和 : " + stats.getSum());
        System.out.println("平均数 : " + stats.getAverage());
    }

结果:
在这里插入图片描述

规约与收集

  • reduce 规约reduce(T identity, BinaryOperator) / reduce(BinaryOperator) -可以将流中元素反复结合起来,得到一个值。
 /**
     * 规约
     */
    @Test
    public void test4(){
        List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);

        //确定有初始值的情况接收
        Integer sum = numbers.stream()
                .reduce(0,(x,y)->x+y);
        System.out.println(sum);

        //不确定有没有初始值
        Optional<Integer> optionalInteger = numbers.stream()
                .reduce(Integer::sum);
        System.out.println(optionalInteger.get());
    }

结果:结果都是25,因为程序比较简单,就不贴图了

  • conllector collect-将流转换为 其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法*/
 /**
    * 收集
    */

   @Test
   public void test5(){
       List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
       List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

       System.out.println("筛选列表: " + filtered);
       String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
       System.out.println("合并字符串: " + mergedString);
   }

结果:
筛选列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl

终止操作(终端操作)

一个终止操作,执行中间操作链,运算得出结果

终端操作就是使用中间操作得到结果的过程,上面的例子已经充分说明了,笔者就不再过多讲述了

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐