Java 8 流peek() API
本文介紹了Java 8 流peek()api,因爲其通常被誤解或誤用。
1. 從示例開始
首先從示例開始,在控制檯中打印字符串流,因爲peek需要Consumer 作爲參數,嘗試代碼如下:
Stream<String> nameStream = Stream.of("Alice", "Bob", "Chuck");
nameStream.peek(System.out::println);
但上述代碼沒有輸出,這是爲什麼?
回顧下流,其有三個部分,數據源,零個或多箇中間操作,零個或多個終止操作。
數據源提供元素給流程。中間操作一個一個獲取元素並處理,所有中間操作是延遲執行,直到流程開始執行纔開始真正執行。終止操作意味着流生命週期結束,更重要的是終止操作啓動流程開始工作。從而提升執行效率,避免中間操作做無用功,底層實現了熔斷機制,只有需要才執行。
因此,上面代碼因爲沒有終止操作,實際並沒有執行,一般流都需要有終止操作啓動流程執行。
2. peek()使用
首先我們修改上面的示例,改用forEach:
Stream<String> nameStream = Stream.of("Alice", "Bob", "Chuck");
nameStream.forEach(System.out::println);
peek官方文檔說明:peek方法主要用於調試,在流程某個步驟查看執行元素情況。
根據官網提示在看個示例:
Stream.of("one", "two", "three", "four")
.filter(e -> e.length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());
這個示例可以觀察到元素流過每個操作的值。除此之外,peek()在另一個場景中也很有用:改變一個元素的內部狀態。例如我們想要在打印所有用戶名之前將其轉換爲小寫:
Stream<User> userStream = Stream.of(new User("Alice"), new User("Bob"), new User("Chuck"));
userStream.peek(u -> u.setName(u.getName().toLowerCase()))
.forEach(System.out::println);
當然也可以使用map,當peek更方便,因爲無需替換元素。
3. 總結
本文我們從流程的生命週期角度理解peek,通過示例介紹了兩個典型使用場景。