您的位置:

Java Stream API

介绍

Java Stream API 是 Java 8 中新引入的一种数据处理方式。它的目标是提供一种简单、高效、并行的处理集合、数组等数据源的方式,以取代原有的 for 循环和迭代器。Java Stream API 通过使用聚合操作(aggregation operation)操纵数据流,获取或转换数据。

前置知识

在深入学习 Java Stream API 之前,我们需要先掌握以下概念:

  • 函数式接口(Functional Interface):函数式接口是只有一个抽象方法的接口。
  • Lambda 表达式:Lambda 表达式 是一种简洁的,代码行数少的而且可传递的对象,可以将 Lambda 表达式看作一段可以传递的代码。它无需命名,旨在简化 Java 程序中单一方法的某些语法的编写。Lambda 方式可以使用 Functional Interface 来实现。

Stream API 的主要特点

Java Stream API 的主要特点可归结为以下几点:

  • 内部迭代:Java Stream API 在迭代时会自动选择并行或顺序执行,无需手动进行线程管理。
  • 一次执行:可以对源数据执行各种中间过程和操作,最终只进行一次完成操作。
  • 不可变:Java Stream API 操作的结果是新流,源数据不变。
  • 延迟执行:Java Stream API 的操作是惰性的,只有在最终执行中间过程的操作时才会被执行。

常用操作

筛选操作

筛选操作指的是通过保留或去除元素来筛选出需要的结果。以下是常用的筛选操作。

filter(Predicate)

filter方法接收一个 Predicate 函数式接口作为参数,返回一个只包含符合条件的元素的 Stream。

Stream<T> filter(Predicate<? super T> predicate)

示例:

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
Stream<String> filtered = strings.stream().filter(string -> !string.isEmpty());
filtered.forEach(System.out::println); //输出不为空的字符串,即除了“”之外的字符串

distinct()

distinct方法返回由不同的元素组成的 Stream。

Stream<T> distinct()

示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 1, 3, 2, 4);
Stream<Integer> distinctNumbers = numbers.stream().distinct();
distinctNumbers.forEach(System.out::println); //输出不重复的整数

映射操作

映射操作指的是将一个流中的元素映射到另一个流中。以下是常用的映射操作。

map(Function)

map方法用于将元素按照指定的 Function 转换成另外的元素。Function 函数式接口接收一个参数并返回一个值。

<R> Stream<R> map(Function<? super T, ? extends R> mapper)

示例:

List<String> strings = Arrays.asList("abc", "efg", "qwerty");
Stream<Integer> mapped = strings.stream().map(String::length); //映射字符串的长度
mapped.forEach(System.out::println); //输出各个字符串的长度

flatMap(Function)

flatMap方法接收一个 Function 函数式接口作为参数,可以将嵌套的 Stream 展平成一个 Stream。

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)

示例:

List<List<String>> list = new ArrayList<>();
list.add(Arrays.asList("apple", "banana"));
list.add(Arrays.asList("orange", "lemon", "grape"));
Stream<String> flatMapped = list.stream().flatMap(Collection::stream);
flatMapped.forEach(System.out::println); //输出展平后的字符串

排序操作

排序操作指对数据集合进行排序。Java Stream API 提供了两种方式进行排序:自然排序和定制排序。

sorted()

sorted方法根据自然排序对源集合进行排序。

Stream<T> sorted()

示例:

List<String> strings = Arrays.asList("ccc", "aaa", "bbb", "ddd");
Stream<String> sorted = strings.stream().sorted();
sorted.forEach(System.out::println); //自然排序

sorted(Comparator)

sorted方法根据指定的 Comparator 接口对源集合进行排序。

Stream<T> sorted(Comparator<? super T> comparator)

示例:

List<String> strings = Arrays.asList("ccc", "aaa", "bbb", "ddd");
Stream<String> sorted = strings.stream().sorted((s1,s2)->s1.length()-s2.length());
sorted.forEach(System.out::println); //按字符串长度排序

聚合操作

聚合操作指获取操作结果的操作,包括归约、收集等操作。

reduce(T identity, BinaryOperator)

reduce方法接收一个初始值和一个 BinaryOperator(t,t)->t 函数,将集合中的元素逐一与上一个结果进行操作,返回一个包含操作结果的 Optional 对象。

T reduce(T identity, BinaryOperator<T> accumulator)

示例:

List<Integer> numbers = Arrays.asList(1,2,3,4);
Optional<Integer> sum = numbers.stream().reduce(0, (x,y)->x+y); //计算整数的和
sum.ifPresent(System.out::println); //输出求和的结果

collect(Collector)

collect方法使用 Collectors 工厂类提供的方法将流转换成集合、映射、字符串等,以操作结果的形式返回。

R collect(Collector<? super T, A, R> collector)

示例:

List<String> strings = Arrays.asList("abc", "def", "ghi");
List<String> collected = strings.stream().filter(s->s.startsWith("a")).collect(Collectors.toList());
collected.forEach(System.out::println); //输出以“a”开头的字符串

小结

Java Stream API 通过内部迭代的方式提供了一种高效、并行的数据处理方式,避免了原有的 for 循环和迭代器的繁琐操作。通过上述常用操作,我们可以方便地对集合、数据进行筛选、映射、排序、聚合等操作,以得到我们预期的结果。通过学习 Java Stream API,我们可以更加轻松地对数据进行操作,提高开发效率。