书接上回,继续研究。
过滤操作(filter)
过滤操作(filter)是 Stream API 中的一种常用操作方法,它接受一个 Predicate 函数作为参数,用于过滤 Stream 中的元素。只有满足 Predicate 条件的元素会被保留下来,而不满足条件的元素将被过滤掉。
过滤操作的语法如下:
Stream<T> filter(Predicate<? super T> predicate)
其中,T
表示 Stream 元素的类型,predicate
是一个函数式接口 Predicate
的实例,它的泛型参数和 Stream 元素类型一致。
使用过滤操作可以根据自定义的条件来筛选出符合要求的元素,从而对 Stream 进行精确的数据过滤。
下面是一个示例,演示如何使用过滤操作筛选出一个整数流中的偶数:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> filteredStream = stream.filter(n -> n % 2 == 0);
filteredStream.forEach(System.out::println); // 输出结果: 2 4
在这个示例中,我们首先创建了一个包含整数的 Stream,并调用 filter()
方法传入一个 Lambda 表达式 n -> n % 2 == 0
,表示要筛选出偶数。然后通过 forEach()
方法遍历输出结果。
需要注意的是,过滤操作返回的是一个新的 Stream 实例,原始的 Stream 不会受到改变。这也是 Stream 操作方法的一个重要特点,它们通常返回一个新的 Stream 实例,以便进行链式调用和组合多个操作步骤。
在实际应用中,过滤操作可以与其他操作方法结合使用,如映射(map)、排序(sorted)、归约(reduce)等,以实现更复杂的数据处理和转换。而过滤操作本身的优点在于,可以高效地对大型数据流进行筛选,从而提高程序的性能和效率。
映射操作(map)
映射操作(map)是 Stream API 中的一种常用操作方法,它接受一个 Function 函数作为参数,用于对 Stream 中的每个元素进行映射转换,生成一个新的 Stream。
映射操作的语法如下:
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
其中,T
表示原始 Stream 的元素类型,R
表示映射后的 Stream 的元素类型,mapper
是一个函数式接口 Function
的实例,它的泛型参数分别是原始 Stream 元素的类型和映射后的元素类型。
使用映射操作可以对 Stream 中的元素逐个进行处理或转换,从而获得一个新的 Stream。这个过程通常涉及对每个元素应用传入的函数,根据函数的返回值来构建新的元素。
下面是一个示例,演示如何使用映射操作将一个字符串流中的每个字符串转换为其长度:
Stream<String> stream = Stream.of("apple", "banana", "cherry");
Stream<Integer> mappedStream = stream.map(s -> s.length());
mappedStream.forEach(System.out::println); // 输出结果: 5 6 6
在这个示例中,我们首先创建了一个包含字符串的 Stream,并调用 map()
方法传入一个 Lambda 表达式 s -> s.length()
,表示要将每个字符串转换为其长度。然后通过 forEach()
方法遍历输出结果。
需要注意的是,映射操作返回的是一个新的 Stream 实例,原始的 Stream 不会受到改变。这也是 Stream 操作方法的一个重要特点,它们通常返回一个新的 Stream 实例,以便进行链式调用和组合多个操作步骤。
在实际应用中,映射操作可以与其他操作方法结合使用,如过滤(filter)、排序(sorted)、归约(reduce)等,以实现更复杂的数据处理和转换。而映射操作本身的优点在于,可以通过简单的函数变换实现对原始数据的转换,减少了繁琐的循环操作,提高了代码的可读性和维护性。
需要注意的是,映射操作可能引发空指针异常(NullPointerException),因此在执行映射操作时,应确保原始 Stream 中不包含空值,并根据具体情况进行空值处理。
排序操作(sorted)
排序操作(sorted)是 Stream API 中的一种常用操作方法,它用于对 Stream 中的元素进行排序。排序操作可以按照自然顺序或者使用自定义的比较器进行排序。
排序操作的语法如下:
Stream<T> sorted()
Stream<T> sorted(Comparator<? super T> comparator)
第一种语法形式中,sorted()
方法会根据元素的自然顺序进行排序。如果元素实现了 Comparable
接口并且具备自然顺序,那么可以直接调用该方法进行排序。
第二种语法形式中,sorted(Comparator<? super T> comparator)
方法接受一个比较器(Comparator)作为参数,用于指定元素的排序规则。通过自定义比较器,可以对非 Comparable
类型的对象进行排序。
下面是一个示例,演示如何使用排序操作对一个字符串流进行排序:
Stream<String> stream = Stream.of("banana", "apple", "cherry");
Stream<String> sortedStream = stream.sorted();
sortedStream.forEach(System.out::println); // 输出结果: apple banana cherry
在这个示例中,我们首先创建了一个包含字符串的 Stream,并直接调用 sorted()
方法进行排序。然后通过 forEach()
方法遍历输出结果。
需要注意的是,排序操作返回的是一个新的 Stream 实例,原始的 Stream 不会受到改变。这也是 Stream 操作方法的一个重要特点,它们通常返回一个新的 Stream 实例,以便进行链式调用和组合多个操作步骤。
在实际应用中,排序操作可以与其他操作方法结合使用,如过滤(filter)、映射(map)、归约(reduce)等,以实现更复杂的数据处理和转换。排序操作本身的优点在于,可以将数据按照特定的顺序排列,便于查找、比较和分析。
需要注意的是,排序操作可能会影响程序的性能,特别是对于大型数据流或者复杂的排序规则。因此,在实际应用中,需要根据具体情况进行权衡和优化,选择合适的算法和数据结构来提高排序的效率。
截断操作(limit 和 skip)
截断操作(limit和skip)是 Stream API 中常用的操作方法,用于在处理流的过程中对元素进行截断。
-
limit(n):保留流中的前n个元素,返回一个包含最多n个元素的新流。如果流中元素少于n个,则返回原始流。
-
skip(n):跳过流中的前n个元素,返回一个包含剩余元素的新流。如果流中元素少于n个,则返回一个空流。
下面分别详细介绍这两个方法的使用。
limit(n) 方法示例:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> limitedStream = stream.limit(3);
limitedStream.forEach(System.out::println); // 输出结果: 1 2 3
在这个示例中,我们创建了一个包含整数的 Stream,并调用 limit(3)
方法来保留前三个元素。然后使用 forEach()
方法遍历输出结果。
skip(n) 方法示例:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> skippedStream = stream.skip(2);
skippedStream.forEach(System.out::println); // 输出结果: 3 4 5
在这个示例中,我们创建了一个包含整数的 Stream,并调用 skip(2)
方法来跳过前两个元素。然后使用 forEach()
方法遍历输出结果。
需要注意的是,截断操作返回的是一个新的 Stream 实例,原始的 Stream 不会受到改变。这也是 Stream 操作方法的一个重要特点,它们通常返回一个新的 Stream 实例,以便进行链式调用和组合多个操作步骤。
截断操作在处理大型数据流或需要对数据进行切分和分页显示的场景中非常有用。通过限制或跳过指定数量的元素,可以控制数据的大小和范围,提高程序的性能并减少不必要的计算。
需要注意的是,在使用截断操作时需要注意流的有界性。如果流是无界的(例如 Stream.generate()
),那么使用 limit()
方法可能导致程序陷入无限循环,而使用 skip()
方法则没有意义。