0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Java的Stream的常用知识

科技绿洲 来源:Java技术指北 作者:Java技术指北 2023-10-11 15:45 次阅读

什么是Stream

生产线

Stream就像处理生产流水线一样去工作,传送带就是Stream的管道,每个工厂关注直接的生产,将上游产品加工成下游需要的产品。为什么Stream比传统的处理方式好呢?我们都知道,传统的处理中,每一步我们都需要通过循环控制,逻辑控制,解包,重新装箱这些工作。

图片
非生产线示意处理图

这些步骤让我们的程序的业务逻辑支离破碎,经常处理数据类的小伙伴尤为痛苦。幸运的是,Java8为我们引入了Stream,使用Stream后我们只关注数据处理逻辑,其他的事情交给流处理对应的方法来完成。

创建数据流

指北君先为大家介绍如何创建Stream,这里有非常多的方式,需要注意一点就是:流一旦创建后,修改创建的源不会影响已经创建的Stream中的数据。

  1. 空流 为了避免出现空指针异常,系统提供一个静态方法提供空流。
public void createStream() {
        Stream< String > myStream = Stream.empty();
    }
  1. 通过数组对象创建流
public void createStream() {
        Integer[] arr = new Integer[]{1,2,3};
        Stream< Integer > stream1 = Arrays.stream(arr);
        Stream< Integer > stream2 = Arrays.stream(arr, 0, 2);
    }
  1. 通过集合对象创建流
public void createStream() {
        Collection< String > collection = Arrays.asList("a", "b", "c");
        Stream< String > stream1 = collection.stream();
    }

支持多种集合:List,Set,Map等实现了Collection接口的集合对象。

  1. 通过builder创建
public void createStream() {
        Stream< Long > stream1 =
                  Stream.< Long >builder().add(1L).add(2L).add(3L).build();
    }
  1. 通过generate生成
public void createStream() {
        Random r = new Random();
        Stream< Long > stream =
                  Stream.generate(() - > r.nextLong()).limit(10);
    }

按照提供给generate的Supplier逻辑生成数据,通过limit限制生成的数据量

  1. 通过Stream.iterate创建
public void createStream() {
        Stream< Integer > stream = Stream.iterate(1, n - > n * n).limit(20);
    }

iterate提供两种方法来满足我们比较常用的迭代生成逻辑

  • iterate(final T seed, final UnaryOperatorf)
  • iterate(T seed, Predicate hasNext, UnaryOperatornext)
  1. 原生类型生成 通过对应的IntStream,LongStream,DoubleStream类中提供的方法来获取,包含常用的方法
  • builder()
  • empty()
  • of()
  • iterate()
  • generate()
  • range()
  • concat()
  1. 其他地方 这里介绍两处:字符分割匹配和文件行数据

String.chars()返回IntStream
Files.lines()返回通过行分割的字符内容

流的使用机制(重要事项)

我们通过上面的方法创建好流后,就可以对流进行相关的业务逻辑处理了,需要注意:如果我们重复对一个流进行操作,就会出错,系统会爆出IllegalStateException异常,这是因为Stream设计为不可重用的模式。流的下一个环节都是对当前环节处理后新生成流的处理。

流的执行顺序

采用Stream方式进行多个逻辑处理时,他们之间的执行顺序是什么样的呢?指北君为了展示效果,写了一段测试代码:

public void exeOrder() {
        List< String > list = Arrays.asList("data_1","data_2", "data_3", "data_12");
        list.stream().filter(x - > {
            System.out.println("filter() was called: " + x);
            return x.contains("2");
        }).map(x - > {
            System.out.println("map() was called: " + x);
            return x.toUpperCase();
        }).forEach(x- >System.out.println("forEach() was called: " + x));
    }

执行结果如下:
filter() was called: data_1
filter() was called: data_2
map() was called: data_2
forEach() was called: data_2
filter() was called: data_3
filter() was called: data_12
map() was called: data_12
forEach() was called: data_12

从示例代码的打印的顺序中我们可以发现:流处理的顺序不是以代码顺序(执行完一步再到下一步),而是按照数据处理完一个单位数据的所有环节再处理下一个数据,见下面的动态示意图:

图片

Stream处理顺序

既然我们了解流的处理顺序,也能理解某些流操作会提前结束流处理的,比如findFirst(),在处理完第一个符合条件的数据后,后续的数据不会参与任何一个环节的处理。

转换处理

转换处理时最常用的逻辑处理方式,介绍转换处理的文章较多,这里不再一一详细描述只是简单列一下,转换处理对应大数据MapReduce中的Map处理

  1. distinct剔重
  2. filter过滤
  3. map转换映射
  4. peek
  5. limit
  6. skip

合并处理(reduce)

对于Map-Reduce模型的reduce操作,国内对这个词翻译不太统一,指北君就先称之为合并处理吧。这里介绍两个方法reduce和collect

  1. reduce 先来看一个reduce的示例
public void reduce() {
        int sum = IntStream.range(1, 100).reduce(0, (a, b) - > a + b);
        System.out.print(sum);
    }

合并Stream中的所有值,合并的初始值为0,如果初始为0还可以省略初始值。reduce函数包含三部分关键信息

  • 初始值,指定合并操作的初始值
  • 合并函数
  • 合路器(函数),在并行(多线程)运算时需要用到

下面是一个使用合路器的示例,在并行运算时使用。

public void parallelReduce() {
        int sum = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).parallelStream()
                .reduce(0, (a, b) - > a + b, (a, b) - > {
                   return a + b;
                });
        System.out.println(sum);
    }

这里指北君留一道思考题给大家,如果这里初始值0修改为10,最终的结果是多少?为什么是这种结果呢?

  1. collect 现在我们再来看collect,collect严格上说是reduce有些牵强,因为是否reduce在于collect中的执行逻辑 比如这段:
List String > collector =  list.stream().map(Product::getName).collect(Collectors.toList());

然后再看下面的例子:

String mergString = list.stream().map(Product::getName).collect(Collectors.joining(", ", "[", "]"));

还有其他对应的方法:

  • Collectors.averagingInt
  • Collectors.summingInt
  • Collectors.groupingBy
  • Collectors.partitioningBy

各位小伙伴可以查看Collectors对应的API,这里就不一一列举了,总之,collect通过Collectors对象的API类完成合并处理。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    8474

    浏览量

    150776
  • JAVA
    +关注

    关注

    19

    文章

    2954

    浏览量

    104511
  • 字符
    +关注

    关注

    0

    文章

    232

    浏览量

    25166
  • 数据处理
    +关注

    关注

    0

    文章

    576

    浏览量

    28517
  • Stream
    +关注

    关注

    0

    文章

    20

    浏览量

    7960
收藏 人收藏

    评论

    相关推荐

    Stream模块的基础用法和进阶用法

    在 Rust 语言中,Tokio 是一个非常流行的异步编程框架。它提供了一系列的模块,其中最常用的就是 Stream 模块。Stream 模块允许我们以异步的方式处理数据流,这在很多情况下非常
    的头像 发表于 09-19 15:33 1141次阅读

    Stream API原理介绍

    Stream API 是 Java 8 中最重要的新特性之一,它是处理集合和数组的一种新方式。它提供了一种简单、灵活和可读的方式来处理集合和数组中的元素,从而使代码更加简洁、高效和易于维护。 1.
    的头像 发表于 09-30 15:31 669次阅读

    JAVA学习直通车(教程+书籍+100个实例+问题与解答)

    对于Java8的并行流并不陌生,没错,我们常常用它来执行并行任务,但是由于并行流(parallel stream)采用的是享线程池,可能会对我们的性能造成严重影响,那怎么处理呢?`
    发表于 10-25 14:35

    JAVA常用系统类的使用 实验

    实验 6 常用系统类的使用 一、实验目的 了解 Java 常用的系统类,包括 Java Applet、字符串类、输入输出流类、数学函数类、日期类、随机数类以及向量类等的基
    发表于 09-23 19:01 1738次阅读

    Java常用工具类

    Java常用工具类。
    发表于 11-06 11:21 1次下载

    JAVA教程之常用图形的绘制与填充

    JAVA教程之常用图形的绘制与填充,很好的JAVA的资料,快来学习吧
    发表于 04-11 17:28 3次下载

    JAVA相关基础知识

    JAVA相关基础知识,感兴趣的小伙伴们可以瞧一瞧。
    发表于 11-10 11:17 0次下载

    Java设计知识讲解

    本文档内容介绍了基于Java设计知识讲解,供参考
    发表于 03-26 11:09 16次下载

    如何利用Stream API来优化Java代码

    使用Stream API优化代码 Java8的新特性主要是Lambda表达式和流,当流和Lambda表达式结合起来一起使用时,因为流申明式处理数据集合的特点,可以让代码变得简洁易读 放大招,流
    的头像 发表于 07-26 14:30 1273次阅读

    JDK8 Stream数据流效率分析

    StreamJava SE 8类库中新增的关键抽象,它被定义于 java.util.stream (这个包里有若干流类型:Stream 代表对象引用流,此外还有一系列特化流,
    的头像 发表于 08-17 10:53 1208次阅读

    javastream编程调试技巧

      javastream编程给调试带来了极大的不便,idea 推出了streamtrace功能,可以详细看到每一步操作的关系、结果,非常方便进行调试。初遇StreamTrace这里简单将字符串转成它的字符数,并设置断点开启debug模式。
    的头像 发表于 10-11 11:06 1546次阅读

    浅析Stream里的隐式转换

    Stream、Flow是在电路描述里经常用到的对象。
    的头像 发表于 05-15 17:36 451次阅读
    浅析<b class='flag-5'>Stream</b>里的隐式转换

    怎么使用Java8的Stream API比较两个List的差异呢?

    可以使用Java8的Stream API来比较两个List的差异,并取出不同的对象。
    的头像 发表于 08-12 11:15 2152次阅读

    Java8的Stream流 map() 方法

    8 之后,对集合可以进行 Stream 操作,使上面的处理更简洁。 概述 Stream 流式处理中有 map() 方法,先看下其定义,该方法在java.util.stream.Stream类中 可以看到
    的头像 发表于 09-25 11:06 1743次阅读
    <b class='flag-5'>Java</b>8的<b class='flag-5'>Stream</b>流 map() 方法

    java常用的包有哪些

    Java是一种面向对象的高级编程语言,它具有平台无关性和可扩展性。Java中有很多常用的包,这些包提供了丰富的类库和工具,用于开发各种类型的应用程序。下面是Java中一些
    的头像 发表于 11-22 15:10 1309次阅读