Java Streams 的潛力

FunTester發表於2024-09-06

Java Streams 是 Java 8 引入後,徹底改變了開發者處理集合的方式。Java Streams 已經成為處理集合的必備工具。它們不僅讓資料處理變得更加簡潔、易讀,還顯著提升了程式碼的可維護性和開發者的生產力。儘管 filtermap 是基本操作,但 Java Streams API 中還有很多值得探索的高階用法。

在這篇文章中,我將介紹 5 個實用技巧,幫助你更好地運用 Java Streams。這些方法不僅能簡化複雜的資料轉換,還能讓你的程式碼更加清晰和高效。

精準過濾

入門

想象一下,你有一個產品列表,想要篩選出有趣的靈魂測試工程師。filter 操作是實現這一目標的利器。來看個例子:

public static void main(String[] args) {  
    List<FunTester> testers = new ArrayList<>();  

    List<FunTester> funTesters = testers.stream()  
            .filter(tester -> tester.getSoul().contains("Fun"))  
            .collect(Collectors.toList());  
}

這段程式碼從 testers 列表中建立了一個流,並透過 filter 篩選出有趣的靈魂(Teseter),最後將結果收集到一個新的 funTesters 列表中。

進階

filter 的強大之處在於你可以輕鬆地組合多個條件。例如,如果你還想篩選出特定類別(比如成年的),可以再加一個 filter

public static void main(String[] args) {  
    List<FunTester> testers = new ArrayList<>();  

    List<FunTester> funTesters = testers.stream()  
            .filter(tester -> tester.getSoul().contains("Fun"))  
            .filter(tester -> tester.getAge() > 18)  
            .collect(Collectors.toList());  
}

透過組合多個條件,你可以更加精準地獲取需要的結果。

map 轉換

入門

map 操作可以對流中的每個元素進行轉換。它接收一個函式(通常是 Lambda 表示式),將其應用於每個元素,生成一個包含轉換結果的新流。

來看個簡單的例子:

public static void main(String[] args) {  
    List<FunTester> testers = new ArrayList<>();  

    List<String> souls = testers.stream()  
            .map(FunTester::getSoul)  
            .collect(Collectors.toList());  
}

在這個例子中,我們使用 map 提取每個 Testersoul,生成一個 String 的列表。

進階

我們可以在 map 之前或之後新增 filter 操作,來篩選和轉換資料。例如,只處理非空的 soul 屬性:

public static void main(String[] args) {  
    List<FunTester> testers = new ArrayList<>();  

    List<String> souls = testers.stream()  
            .map(FunTester::getSoul)  
            .filter(Objects::nonNull) // 過濾掉空值  
            .map(String::trim) // 去除首尾空格  
            .collect(Collectors.toList());  
}

map 的用途非常廣泛,不僅限於簡單的資料提取,還能用於更復雜的轉換。

彙總

入門

reduce 操作可以將流中的元素累積成一個單一結果,非常適合進行統計或資料彙總。比如,計算所有 Tester 的 BUG 總數:

public static void main(String[] args) {  
    List<FunTester> testers = new ArrayList<>();  

    int bugs = testers.stream()  
            .mapToInt(FunTester::getBugs)// 獲取所有測試工程師的 bug 數量  
            .reduce(0, Integer::sum);// 計算總 bug 數量  
}

這段程式碼演示瞭如何使用 Java Streams API 高效地計算 List 中所有 FunTester 物件的 BUG 總數。使用 mapToInt 提取 int 值並透過 reduce 計算總和是處理這類問題的常見模式。這種方法簡潔而強大,適用於各種類似的資料處理場景。

進階

reduce 還能用於其他型別的彙總操作。比如,找出最便宜的商品:

FunTester funTester = testers.stream()  
        .reduce((t1, t2) -> t1.getBugs() > t2.getBugs() ? t1 : t2)  
        .get();  
System.out.println("BUG 最多的靈魂測試工程師是:" + funTester.getName());

在這個例子中,reduce 用於比較每個 Tester 的 BUG 數量,找出 BUG 最多的那個,把他揪出來。

分組

基礎

groupBy 是 Java Streams API 中的一個強大功能,它允許你根據某個特性將流中的元素分組。透過 groupBy,你可以將具有相似屬性的元素歸類到同一個集合中,從而方便地進行進一步的分析和處理。

比如將 Tester 根據司齡進行分組:

Map<Integer, List<FunTester>> collect = testers.stream()
.collect(Collectors.groupingBy(FunTester::getCompanyYears));

程式碼演示瞭如何使用 Java Streams API 將 FunTester 物件按司齡(getCompanyYears)進行分組。以下是完整示例,展示瞭如何按工作年限對 FunTester 物件進行分組,並輸出分組結果。

進階

Java Streams 甚至支援巢狀分組。例如可以先根據司齡進行分組,然後再根據實際年齡分組。

public static void main(String[] args) {  
    List<FunTester> testers = new ArrayList<>();  

    Map<Integer, Map<String, List<FunTester>>> collect = testers.stream()  
            .collect(Collectors.groupingBy(FunTester::getCompanyYears, Collectors.groupingBy(t -> {  
        if (t.getAge() > 35) {// 年齡大於35歲,則分組  
            return "年齡大";  
        } else {  
            return "年齡小";  
        }  
    })));  
}

透過巢狀的 groupingBy,你可以將資料進行多層次的分組,使得組織資料更為靈活。

Java Streams 的潛力

Java Streams 的強大功能遠不止於此。隨著你深入探索這個 API 的更多特性,你會發現它不僅能幫助你處理集合資料,還能極大地提升程式碼的可讀性和維護性。透過不斷實踐和應用,你將逐漸掌握這些工具的精髓,使得程式碼變得更加高效、簡潔、優雅。不論是處理複雜的資料轉換,還是實現更靈活的操作,Java Streams 都能為你提供無窮的可能性,讓你的程式設計技巧更上一層樓。

FunTester 原創精華
  • 服務端功能測試
  • 效能測試專題
  • Java、Groovy、Go
  • 白盒、工具、爬蟲、UI 自動化
  • 理論、感悟、影片
如果覺得我的文章對您有用,請隨意打賞。您的支援將鼓勵我繼續創作!
打賞支援

相關文章