Stories

Detail Return Return

探索 Java 中的 Stream API:優雅處理集合的利器 - Stories Detail

Java 8 引入了一個功能強大的工具——Stream API,極大地簡化了對集合的操作。傳統上,Java 程序員習慣使用 for 循環來遍歷集合並進行過濾、映射等操作,這種方式雖然直觀但代碼冗長且難以維護。Stream API 通過流式編程的方式,使得我們能夠以更簡潔和優雅的方式操作集合。

本文將介紹 Java Stream API 的基本概念及其常見的使用場景,幫助你更好地掌握這一工具。

一、什麼是 Stream?

Stream 是一種用於處理集合的高級抽象。它並不是數據結構,而是一種可以在元素上執行聚合操作的流,比如 filter(過濾)、map(映射)、reduce(歸約)等操作。Stream API 的核心思想是聲明式編程,通過鏈式調用來描述數據處理過程。

需要注意的是,Stream 本身並不會存儲數據,它是一個“流”,可以從集合、數組或 I/O 資源中獲取數據,並通過一系列中間操作和終結操作來處理數據。

二、Stream 的基本操作

Stream API 的操作可以分為兩類:

  1. 中間操作(Intermediate Operations):返回新的 Stream,可以被鏈式調用,但不會觸發實際計算。例如:filtermapsorted 等。
  2. 終結操作(Terminal Operations):觸發 Stream 計算並返回結果,比如 forEachcollectreduce 等。一旦執行終結操作,Stream 就會關閉。

示例集合

我們使用一個簡單的整數列表來演示 Stream 的基本操作:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

三、常用的 Stream 操作

1. filter:過濾

filter 方法用於對 Stream 中的元素進行篩選,保留符合條件的元素。它接受一個謂詞(返回 boolean 的 lambda 表達式)作為參數。

List<Integer> evenNumbers = numbers.stream()
                                   .filter(n -> n % 2 == 0)
                                   .collect(Collectors.toList());
System.out.println(evenNumbers); // 輸出:[2, 4, 6, 8, 10]

在上面的代碼中,filter 方法過濾掉了所有的奇數,保留了偶數。

2. map:映射

map 方法將每個元素映射為另一個值,常用於將集合中的元素轉換成其他類型。

List<Integer> squares = numbers.stream()
                               .map(n -> n * n)
                               .collect(Collectors.toList());
System.out.println(squares); // 輸出:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

在這裏,map 方法將每個元素都平方並返回一個新的 Stream。

3. sorted:排序

sorted 方法用於對 Stream 中的元素進行排序。默認是升序排序,也可以傳入自定義比較器來指定排序規則。

List<Integer> sortedNumbers = numbers.stream()
                                     .sorted(Comparator.reverseOrder())
                                     .collect(Collectors.toList());
System.out.println(sortedNumbers); // 輸出:[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

在這個例子中,我們使用 Comparator.reverseOrder() 實現了降序排序。

4. collect:收集

collect 是一個終結操作,用於將 Stream 中的元素收集到某種結果中,比如列表、集合或字符串。Collectors 類提供了一系列工廠方法來方便地執行這種收集操作。

List<Integer> evenNumbers = numbers.stream()
                                   .filter(n -> n % 2 == 0)
                                   .collect(Collectors.toList());
System.out.println(evenNumbers); // 輸出:[2, 4, 6, 8, 10]

上例中,collect 方法將流的元素收集到一個 List 中。

5. reduce:歸約

reduce 操作可以將 Stream 中的所有元素組合成一個結果,它經常用於求和、求積等聚合操作。

int sum = numbers.stream()
                 .reduce(0, Integer::sum);
System.out.println(sum); // 輸出:55

在這裏,reduce 方法將所有元素相加並返回總和。

四、Stream 的惰性求值

Stream 的中間操作是惰性求值的。這意味着即使鏈式調用了多箇中間操作,也不會立即執行,只有在遇到終結操作時才會執行計算。這種特性使得 Stream 可以進行延遲加載,避免不必要的計算,提高性能。

例如:

List<Integer> processedNumbers = numbers.stream()
                                        .filter(n -> {
                                            System.out.println("Filter: " + n);
                                            return n % 2 == 0;
                                        })
                                        .map(n -> {
                                            System.out.println("Map: " + n);
                                            return n * n;
                                        })
                                        .collect(Collectors.toList());
System.out.println(processedNumbers);

在上面的代碼中,只有在 collect 方法被調用時,filtermap 操作才會真正執行。每個元素會依次經過 filtermap 處理,輸出如下:

Filter: 1
Filter: 2
Map: 2
Filter: 3
Filter: 4
Map: 4
...

這種惰性求值的特性使得 Stream 能夠避免重複遍歷,提高效率。

五、Stream 的並行處理

Java 8 引入了 parallelStream 方法,允許我們輕鬆地將 Stream 轉換為並行流。在並行流中,多個線程會並行地處理 Stream 中的元素,利用多核 CPU 的優勢來提高性能。

int sumOfSquares = numbers.parallelStream()
                          .map(n -> n * n)
                          .reduce(0, Integer::sum);
System.out.println(sumOfSquares); // 輸出:385

在並行流中,mapreduce 操作會並行執行,可以顯著縮短處理時間。然而,並行流並不總是能提高性能,在數據量較小或者有複雜依賴的情況下,可能會增加不必要的開銷。

六、Stream API 的應用場景

Stream API 尤其適用於以下場景:

  • 數據過濾:快速篩選集合中的元素。
  • 數據轉換:將一個類型的數據轉換為另一種類型。
  • 數據聚合:求和、求平均數、最值等操作。
  • 並行處理:在大量數據處理時,提高處理速度。

例如,假設我們有一個 Person 對象的列表,想要找出所有年齡大於 18 歲的名字,並按年齡排序:

List<Person> people = Arrays.asList(
    new Person("Alice", 23),
    new Person("Bob", 17),
    new Person("Charlie", 19)
);

List<String> adultNames = people.stream()
                                .filter(person -> person.getAge() > 18)
                                .sorted(Comparator.comparingInt(Person::getAge))
                                .map(Person::getName)
                                .collect(Collectors.toList());
System.out.println(adultNames); // 輸出:[Charlie, Alice]

這種流式處理的方式使代碼更加簡潔明瞭。

七、總結

Java Stream API 提供了一種聲明式、簡潔、高效的方式來處理集合數據。通過 filtermapsorted 等操作,開發者可以輕鬆地完成複雜的數據處理任務,而不用編寫冗長的 for 循環。Stream API 的惰性求值和並行處理特性也為性能優化提供了支持。

掌握 Stream API 不僅能提升代碼的可讀性,也能顯著提高 Java 應用的開發效率。

user avatar toopoo Avatar alibabawenyujishu Avatar freeman_tian Avatar jingdongkeji Avatar qingzhan Avatar razyliang Avatar linx Avatar qian5201314 Avatar paolongtaodeniupai Avatar yqyx36 Avatar guixiangyyds Avatar ccVue Avatar
Favorites 176 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.