天天看點

Java8 Stream 的這些知識,你了解嗎

作者:Java4ye

小夥伴們好呀,我是 小羊,今天來和大家分享下這個 Stream 。

Java8 Stream 的這些知識,你了解嗎

目錄

什麼是流呢?

想了好久也不知道怎麼表述,感覺很抽象,就是一個很好用的工具。

認真點說辭

對 Java集合 的增強,提供了 過濾,計算,轉換 等聚合操作,使用起來友善快捷。

詳解

Java8 Stream 的這些知識,你了解嗎

來自 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 一樣。
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 不熟悉的,可以看看這個部落客的例子

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

總結

看完之後,要記得

stream 是一次性的,不是資料結構,不存儲資料,不改變源資料.。

API 分為終端和中間操作,中間操作是惰性的,碰到終端才去執行。

同時中間操作有無狀态和有狀态之分,有狀态需要更改上一步操作獲得的所有元素,才可以進行下一步操作,比如 排序 sorted,去重 distinct,跳過 skip,限制 limit 這四個,需要多疊代一次。

終端操作有短路與否之分,短路操作有 anyMatch, allMatch, noneMatch, findFirst, findAny

不過,現在我對它的源碼更感興趣了,找個時間再研究研究✍

喜歡的小夥伴記得關注點點贊哦,全網同名[狗頭]