Java Stream API 是 Java 8 引入的一个重要特性,它提供了一种高效且易于使用的处理集合的方式。Stream API 支持函数式编程风格,可以对集合进行复杂的转换和操作,如过滤、映射、排序、聚合等。
Stream API 的基本概念
Stream API 主要有三个核心组件:
- 源(Source):数据流的来源,通常是集合(如
List
、Set
等)或其他数据结构。 - 中间操作(Intermediate Operations):一系列可以按顺序链接在一起的数据处理操作,如
filter
、map
、sorted
等。 - 终止操作(Terminal Operations):结束流的操作,产生最终结果或副作用,如
collect
、forEach
、findFirst
等。
Stream API 的基本使用
创建 Stream
创建 Stream 的常见方式有:
-
从集合创建 Stream:
- 使用集合的
stream()
或parallelStream()
方法创建 Stream。
- 使用集合的
-
从数组创建 Stream:
- 使用
Arrays.stream(array)
方法创建 Stream。
- 使用
-
从迭代器创建 Stream:
- 使用
Stream.iterate(seed, next)
方法创建无限流。
- 使用
-
从生成器创建 Stream:
- 使用
Stream.generate(generator)
方法创建无限流。
- 使用
中间操作(Intermediate Operations)
中间操作可以链接在一起,形成流水线式的处理过程。常见的中间操作包括:
filter(Predicate<T> predicate)
:筛选元素。map(Function<T, R> mapper)
:转换元素。flatMap(Function<T, Stream<R>> mapper)
:将嵌套的 Stream 展平。distinct()
:去重。sorted()
:排序。peek(Consumer<T> action)
:打印或调试输出。
终止操作(Terminal Operations)
终止操作结束 Stream,产生最终结果或副作用。常见的终止操作包括:
forEach(Consumer<T> action)
:遍历流中的每个元素。collect(Collector<T, A, R> collector)
:收集流中的元素。reduce(BinaryOperator<T>)
:聚合流中的元素。anyMatch(Predicate<T> predicate)
:判断是否有元素满足条件。allMatch(Predicate<T> predicate)
:判断所有元素是否满足条件。noneMatch(Predicate<T> predicate)
:判断是否有元素不满足条件。findFirst()
:获取第一个元素。findAny()
:获取任意一个元素。count()
:计算元素数量。max(Comparator<T> comparator)
:获取最大元素。min(Comparator<T> comparator)
:获取最小元素。
示例代码
示例 1:基本使用
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 过滤偶数
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println(evenNumbers); // 输出 [2, 4, 6, 8, 10]
// 映射平方
List<Integer> squares = numbers.stream()
.map(n -> n * n)
.collect(Collectors.toList());
System.out.println(squares); // 输出 [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
// 排序
List<Integer> sortedNumbers = numbers.stream()
.sorted((a, b) -> b - a)
.collect(Collectors.toList());
System.out.println(sortedNumbers); // 输出 [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
// 去重
List<Integer> uniqueNumbers = numbers.stream()
.distinct()
.collect(Collectors.toList());
System.out.println(uniqueNumbers); // 输出 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] (原列表已经是唯一的)
// 遍历输出
numbers.stream()
.forEach(System.out::println);
// 打印每个元素
numbers.stream()
.peek(System.out::println)
.collect(Collectors.toList());
}
}
示例 2:复杂操作
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class ComplexStreamExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");
// 过滤长度大于 5 的名字,并转换成大写
List<String> longNamesUpper = names.stream()
.filter(name -> name.length() > 5)
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(longNamesUpper); // 输出 [CHARLIE, DAVID]
// 计算名字长度的总和
int totalLength = names.stream()
.mapToInt(String::length)
.sum();
System.out.println(totalLength); // 输出 23
// 检查是否有名字长度大于 5
boolean hasLongName = names.stream()
.anyMatch(name -> name.length() > 5);
System.out.println(hasLongName); // 输出 true
// 获取最长的名字
String longestName = names.stream()
.max(Comparator.comparingInt(String::length))
.orElse(null);
System.out.println(longestName); // 输出 Charlie
// 获取最短的名字
String shortestName = names.stream()
.min(Comparator.comparingInt(String::length))
.orElse(null);
System.out.println(shortestName); // 输出 Bob
// 分组统计每个名字的长度出现次数
Map<Integer, Long> lengthCount = names.stream()
.collect(Collectors.groupingBy(String::length, Collectors.counting()));
System.out.println(lengthCount); // 输出 {3=2, 5=1, 6=1, 7=1}
// 归约操作
int product = names.stream()
.mapToInt(name -> name.length())
.reduce(1, (a, b) -> a * b);
System.out.println(product); // 输出 34560
}
}
Stream API 的高级用法
1. 并行流(Parallel Streams)
并行流可以提高处理大量数据时的效率。
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
public class ParallelStreamExample {
public static void main(String[] args) {
Random random = new Random();
List<Integer> numbers = IntStream.rangeClosed(1, 1000000)
.boxed()
.collect(Collectors.toList());
// 使用并行流计算总和
long parallelSum = numbers.parallelStream()
.reduce(0L, Long::sum);
System.out.println(parallelSum); // 输出 500000500000
}
}
2. 构建复杂的数据结构
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class ComplexDataStructureExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");
// 构建一个 Map,键是名字长度,值是对应的名字列表
Map<Integer, List<String>> lengthToNames = names.stream()
.collect(Collectors.groupingBy(String::length));
System.out.println(lengthToNames); // 输出 {3=[Bob, Eve], 5=[Alice], 7=[Charlie], 6=[David]}
}
}
总结
Java Stream API 提供了一种高效且易于使用的处理集合的方式。通过使用 Stream API,可以轻松实现复杂的集合操作,如过滤、映射、排序、聚合等。掌握 Stream API 的基本概念和用法后,可以更好地利用这些特性来编写高效、简洁的 Java 应用程序。
通过上述示例代码,可以看到 Stream API 如何简化集合操作,并提供更多的功能和灵活性。无论是简单的筛选和映射,还是复杂的聚合和分组,Stream API 都能够胜任。