• Java8 Stream 的这些知识,你了解吗


    今天来和大家分享下这个 Stream

    什么是流呢?

    想了好久也不知道怎么表述,感觉很抽象,就是一个很好用的工具🐖。

    认真点说辞👇

    Java集合 的增强,提供了 过滤,计算,转换 等聚合操作,使用起来方便快捷。

    详解👇

    流 和 集合 的不同点

    为了弄明白这个 stream 是啥,我还特意去翻看了 Java SE 的文档🐖,今年第一次打开 哈哈哈

    👉 docs.oracle.com/javase/8/do…

    1. 流不是数据结构,不存储数据
    2. 流不改变数据源的数据,比如 filter 一个集合时,最后是返回一个新集合,而不是删除原集合中的对象
    3. 流的 API 分为 中间操作终端操作中间操作是惰性的,遇到终端操作才真正执行
    4. 流是无限的,集合是有限的,可以通过 limit ,findFirst 等 短路 API 来让它快点执行完
    5. 是一次性的,使用后就关闭了,需要重新创建,和 Iterator 一样。

    流的创建

    看文档里有很多种创建方式,stream(),Stream.of(),Arrays.stream() 等,不过我平时使用最多的还是 stream() 这种。

    这里要稍微注意下这个 Stream.of()stream()区别

    Stream.of() 会把传进去的参数当作 元素 处理,而 stream()Collection 接口中新增的默认方法,它本来就是用来处理 集合中的每一个元素 的。

    但是 Stream.of() 也可以利用 flatMap 这个函数来展开集合中的元素,达成相应的目的

    1. //       Stream.of(data) 把集合当作整体处理,不是处理其中的元素
    2. //       stream(data) 处理集合中的元素
    3. int[] data = {4, 5, 3, 6, 2, 5, 1};
    4. Stream.of(data)
    5.       .flatMap(e -> Arrays.stream(e).boxed()).collect(Collectors.toList())
    6.       .forEach(System.out::println);
    7. Arrays.stream(data).boxed().collect(Collectors.toList()).forEach(System.out::println);
    8. 复制代码

    中间操作

    这里有下面两种状态区分

    • 无状态:无需等待上一步的操作
    • 有状态:需要获取上一步操作的所有元素后才可以进行下一步操作,会多迭代一次,就比如 sorted,会将之前的所有元素进行排序,然后再进行下一步操作

    这部分的 API 如下,也比较简单,文末再给个小例子🐖

    终端操作

    这里就是产生结果的了。

    API 分为 短路操作与否。

    数组,集合,包装类,基本数据类型之间的转换

    这个我也是老忘记~ 🐖

    1. // int[] 转 List<Integer>
    2. // 这里用到了 数组流 的创建方式,通过 Arrays.stream(data) 将其变成 IntStream,调用 boxed 变成包装类,最后转成集合。
    3. List<Integer> list1 = Arrays.stream(data).boxed().collect(Collectors.toList());
    4. // int[] 转 Integer[]
    5. // 同上,转成数组用 toArray
    6. Integer[] integer1 = Arrays.stream(data).boxed().toArray(Integer[]::new);
    7. // List<Integer> 转 Integer[]
    8. // 集合转数组,直接用 toArray 即可
    9. Integer[] integers2 = list1.toArray(new Integer[0]);
    10. // List<Integer> 转 int[]
    11. // 装箱拆箱,得通过 IntStream 来实现
    12. int[] arr1 = list1.stream().mapToInt(Integer::valueOf).toArray();
    13. // Integer[] 转 int[]
    14. // 同样的,装箱拆箱,得通过 IntStream 来实现
    15. int[] arr2 = Arrays.stream(integer1).mapToInt(Integer::valueOf).toArray();
    16. // Integer[] 转 List<Integer>
    17. List<Integer> list2 = Arrays.asList(integer1);
    18. 复制代码

    小例子

    1. public static void main(String[] args) {
    2.       String str = "Java4ye";
    3.       Student aStud = new Student(1, "a");
    4.       Student bStud = new Student(2, "b");
    5.       Student cStud = new Student(3, null);
    6.       // 集合的创建 一
    7.       List<Student> collect1 = Stream.of(aStud, bStud, cStud).collect(Collectors.toList());
    8.       collect1.forEach(System.out::println);
    9.       // 集合的创建 二
    10.       List<Student> studentList = new ArrayList<>();
    11.       studentList.add(aStud);
    12.       studentList.add(bStud);
    13.       studentList.add(cStud);
    14.       List<String> studNameList = studentList.stream()
    15.               .map(Student::getName)
    16.               .filter(Objects::nonNull)
    17.               .map(String::toUpperCase)
    18.               .sorted()
    19.               .map(e -> e + "c")
    20.               .collect(Collectors.toList());
    21.       studNameList.forEach(System.out::println);
    22.       // toMap 要注意 Duplicate key 的问题,需要 merge 处理,其他的 map 等获取属性时,要提防 null
    23.       Map<String, Student> collect = studentList.stream()
    24.               .collect(
    25.                       Collectors.toMap(
    26.                               Student::getName,
    27.                               e -> e,
    28.                               (a, b) -> {
    29.                                   if (a.getAge() > b.getAge()) {
    30.                                       return a;
    31.                                   }
    32.                                   return b;
    33.                               }
    34.                               )
    35.               );
    36.       collect.forEach((s, student) -> System.out.println(student));
    37.   }
    38. 复制代码

    IDEA 自带的 debug 可以清楚看到每一步获取到的数据😋

    总结

    看完之后,要记得

    stream 是一次性的,不是数据结构,不存储数据,不改变源数据.。

    API 分为终端和中间操作,中间操作是惰性的,碰到终端才去执行。

    同时中间操作有无状态和有状态之分,有状态需要更改上一步操作获得的所有元素,才可以进行下一步操作,比如 排序 sorted,去重 distinct,跳过 skip,限制 limit 这四个,需要多迭代一次。

    终端操作有短路与否之分,短路操作有 anyMatch, allMatch, noneMatch, findFirst, findAny

    不过,现在我对它的源码更感兴趣了,找个时间再研究研究✍

  • 相关阅读:
    Visual Studio 线性表的链式存储节点输出引发异常:读取访问权限冲突
    如何实现数据通过表格批量导入数据库
    内存与CPU:计算机默契交互的关键解析
    踩坑笔记: 基于 rust-analyzer 在 vscode 中进行 rust 开发配置问题
    动态内存分配 指针类型转换
    阿里云的CIPU
    嵌入式Linux应用开发基础知识——GCC编译过程
    javaee springMVC 一个案例
    生物通路数据库收录1600+整合的经典通路
    C++基础知识(五)--- 智能指针类&字符串类
  • 原文地址:https://blog.csdn.net/m0_73311735/article/details/127864112