likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 21

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

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

什么是流呢?

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

认真点说辞👇

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

详解👇

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

流 和 集合 的不同点

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

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

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

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

流的创建

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

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

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

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

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

//        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);

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

中间操作

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

这里有下面两种状态区分

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

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

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

终端操作

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

这里就是产生结果的了。

API 分为 短路操作与否。

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

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

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

这个我也是老忘记~ 🐖

// 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);

小例子

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 可以清楚看到每一步获取到的数据😋

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

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

blog.csdn.net/mu_wind/art…

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

总结

看完之后,要记得

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

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

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

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

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