前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java8 Stream 设计思路解析和使用

Java8 Stream 设计思路解析和使用

原创
作者头像
Java4ye
发布2024-01-31 11:38:02
2120
发布2024-01-31 11:38:02
举报
文章被收录于专栏:Java专栏Java 专栏Java专栏

小伙伴们好呀,我是 小羊,今天来和大家分享下这个 Stream

目录
目录

什么是流呢?

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

认真点说辞👇

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

详解👇

来自 https://www.logicbig.com/tutorials/core-java-tutorial/java-util-stream/stream-api-intro.html
来自 https://www.logicbig.com/tutorials/core-java-tutorial/java-util-stream/stream-api-intro.html

流 和 集合 的不同点

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

👉 https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

  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 这个函数来展开集合中的元素,达成相应的目的

代码语言:java
复制
//        Stream.of(data) 把集合当作整体处理,不是处理其中的元素
//        stream(data) 处理集合中的元素

int[] data = {4, 5, 3, 6, 2, 5, 1};

Stream.of(data)
        .flatMap(e -> Arrays.stream(e).boxed()).collect(Collectors.toList())
        .forEach(System.out::println);

Arrays.stream(data).boxed().collect(Collectors.toList()).forEach(System.out::println);

中间操作

这里有下面两种状态区分

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

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

终端操作

这里就是产生结果的了。

API 分为 短路操作与否。

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

这个我也是老忘记~ 🐖

代码语言:java
复制
// int[] 转 List<Integer>
// 这里用到了 数组流 的创建方式,通过  Arrays.stream(data) 将其变成 IntStream,调用 boxed 变成包装类,最后转成集合。
 List<Integer> list1 = Arrays.stream(data).boxed().collect(Collectors.toList());

 // int[] 转 Integer[]
 // 同上,转成数组用 toArray 
 Integer[] integer1 = Arrays.stream(data).boxed().toArray(Integer[]::new);

 // List<Integer> 转 Integer[]
 // 集合转数组,直接用 toArray 即可
 Integer[] integers2 = list1.toArray(new Integer[0]);

 // List<Integer> 转 int[]
 // 装箱拆箱,得通过 IntStream 来实现 
 int[] arr1 = list1.stream().mapToInt(Integer::valueOf).toArray();

 // Integer[] 转 int[]
 // 同样的,装箱拆箱,得通过 IntStream 来实现
 int[] arr2 = Arrays.stream(integer1).mapToInt(Integer::valueOf).toArray();
 
 // Integer[] 转 List<Integer>
 List<Integer> list2 = Arrays.asList(integer1);

小例子

代码语言:Java
复制
public static void main(String[] args) {
        String str = "Java4ye";

        Student aStud = new Student(1, "a");
        Student bStud = new Student(2, "b");
        Student cStud = new Student(3, null);

        // 集合的创建 一
        List<Student> collect1 = Stream.of(aStud, bStud, cStud).collect(Collectors.toList());
        collect1.forEach(System.out::println);

        // 集合的创建 二
        List<Student> studentList = new ArrayList<>();
        studentList.add(aStud);
        studentList.add(bStud);
        studentList.add(cStud);

        List<String> studNameList = studentList.stream()
                .map(Student::getName)
                .filter(Objects::nonNull)
                .map(String::toUpperCase)
                .sorted()
                .map(e -> e + "c")
                .collect(Collectors.toList());

        studNameList.forEach(System.out::println);

        // toMap 要注意 Duplicate key 的问题,需要 merge 处理,其他的 map 等获取属性时,要提防 null

        Map<String, Student> collect = studentList.stream()
                .collect(
                        Collectors.toMap(
                                Student::getName,
                                e -> e,
                                (a, b) -> {
                                    if (a.getAge() > b.getAge()) {
                                        return a;
                                    }
                                    return b;
                                }
                                )
                );

        collect.forEach((s, student) -> System.out.println(student));

    }

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

对 API 不熟悉的,可以看看这个博主的例子👇

https://blog.csdn.net/mu_wind/article/details/109516995#t1

赞

总结

看完之后,要记得

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

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

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

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

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是流呢?
  • 流 和 集合 的不同点
  • 流的创建
  • 中间操作
  • 终端操作
  • 数组,集合,包装类,基本数据类型之间的转换
  • 小例子
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档