一、Stream简介
在介绍Java Stream Peek之前,先需要了解Java Stream的概念。Java Stream是在Java 8之后引入的一种新的处理数据集合的方式,它可以更简便、高效地操作集合中的数据。与传统的集合操作方式相比,Java Stream可以提高性能和代码可读性。
Java Stream是一个表示任意元素序列的概念,它支持各种类型的数据源,例如List、Set、数组等,Stream操作可以分为中间操作和终端操作两类。中间操作包括过滤、映射、排序、去重等操作,而终端操作包括forEach、count、collect等。
二、Stream Peek的作用
Stream Peek是Stream中的一个中间操作,它可以让我们在Stream中执行一些诊断性的操作,例如打印出Stream中的元素、记录日志、计算执行时间等。Stream Peek可以帮助我们更好地了解Stream的数据流向,也可以在调试代码时提供一些帮助。
Stream Peek的签名如下:
Streampeek(Consumer action);
其中,action代表一个Consumer类型的函数式接口,它可以在Stream的每个元素上执行一些操作。
三、Stream Peek的使用场景
Stream Peek适用于以下一些场景:
1、观察Stream的数据流向
在对Stream进行多个操作时,我们有时难以确定Stream中数据的真实状态,即Stream中的元素究竟是什么样子的。此时,可以在每个中间操作之后插入一个peek操作,打印出当前Stream中的元素,以便我们观察Stream的数据流向。例如:
List<String> list = Arrays.asList("apple", "banana", "orange", "watermelon"); list.stream().filter(s -> s.length() > 5) .peek(s -> System.out.println("filter:" + s)) .map(String::toUpperCase) .peek(s -> System.out.println("toUpperCase:" + s)) .collect(Collectors.toList());
执行结果如下:
filter:orange toUpperCase:ORANGE filter:watermelon toUpperCase:WATERMELON
打印出了Stream中经过过滤和映射之后的元素,以便我们更清楚地了解Stream的数据流向。
2、记录日志
在开发中,我们经常需要记录一些日志信息以便追踪问题。Stream Peek可以方便地记录一些Stream中的信息。例如,在以下的示例中,我们在Stream Peek中打印出当前处理的数字:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); list.stream().peek(i -> System.out.println("processing:" + i)) .map(i -> i * 2) .peek(i -> System.out.println("result:" + i)) .collect(Collectors.toList());
执行结果如下:
processing:1 result:2 processing:2 result:4 processing:3 result:6 processing:4 result:8 processing:5 result:10
可以看到,在Stream Peek中,我们输出了每个数字的处理过程和结果,方便我们日后进行追踪和调试。
四、Stream Peek的注意事项
当使用Stream Peek时,需要注意以下事项:
1、Stream Peek是中间操作
与终端操作不同,Stream Peek是中间操作,它不能打断Stream的处理过程。如果在Stream Peek中抛出异常,那么Stream的处理将会中断。
2、Stream Peek不能修改Stream中的元素
Stream Peek只是对Stream中的元素进行一些操作,它不能修改Stream中的元素。如果需要对Stream进行修改,应该使用map等终端操作。
3、Stream Peek可以执行多次
与终端操作不同,Stream Peek是可以执行多次的,每次执行都会打印出当前Stream中的元素。例如:
List<String> list = Arrays.asList("apple", "banana", "orange", "watermelon"); Stream<String> stream = list.stream(); stream.peek(s -> System.out.println("peek1:" + s)) .filter(s -> s.length() > 5) .peek(s -> System.out.println("peek2:" + s)) .map(String::toUpperCase) .peek(s -> System.out.println("peek3:" + s)) .collect(Collectors.toList()); stream.peek(s -> System.out.println("peek4:" + s)) .map(String::toLowerCase) .peek(s -> System.out.println("peek5:" + s)) .collect(Collectors.toList());
执行结果如下:
peek1:apple peek1:banana peek1:orange peek1:watermelon peek2:watermelon peek3:WATERMELON peek2:orange peek3:ORANGE peek4:apple peek4:banana peek4:orange peek4:watermelon peek5:orange peek5:watermelon peek5:apple peek5:banana
可以看到,在两个不同的Stream中执行了多个peek操作。
五、代码示例
以下为一个完整的Java Stream Peek的代码示例:
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamPeekExample { public static void main(String[] args) { // 观察Stream的数据流向 List<String> list = Arrays.asList("apple", "banana", "orange", "watermelon"); list.stream().filter(s -> s.length() > 5) .peek(s -> System.out.println("filter:" + s)) .map(String::toUpperCase) .peek(s -> System.out.println("toUpperCase:" + s)) .collect(Collectors.toList()); // 记录日志 List<Integer> list2 = Arrays.asList(1, 2, 3, 4, 5); list2.stream().peek(i -> System.out.println("processing:" + i)) .map(i -> i * 2) .peek(i -> System.out.println("result:" + i)) .collect(Collectors.toList()); // 可以执行多次 Stream<String> stream = list.stream(); stream.peek(s -> System.out.println("peek1:" + s)) .filter(s -> s.length() > 5) .peek(s -> System.out.println("peek2:" + s)) .map(String::toUpperCase) .peek(s -> System.out.println("peek3:" + s)) .collect(Collectors.toList()); stream.peek(s -> System.out.println("peek4:" + s)) .map(String::toLowerCase) .peek(s -> System.out.println("peek5:" + s)) .collect(Collectors.toList()); } }