Java Stream流详解:用法与常用API实战
1. 什么是Stream流?
Java 8 引入了 Stream API,它提供了一种高效、声明式的方式来处理集合数据。Stream 不是数据结构,而是对数据源(如集合、数组等)进行高效聚合操作(如过滤、映射、排序等)的工具。
Stream 的特点:
不存储数据:Stream 本身不存储元素,它只是从数据源(如集合)获取数据并进行操作。
不修改源数据:Stream 的操作不会改变原始数据源,而是生成新的流。
惰性执行:许多 Stream 操作(如
filter
、map
)是惰性的,只有在终端操作(如collect
、forEach
)触发时才会执行。可并行化:Stream 可以轻松转换为并行流(
parallelStream
),以利用多核 CPU 提升性能。
2. Stream 的创建方式
Stream 可以通过多种方式创建:
(1)从集合创建
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); Stream<String> stream = names.stream(); // 顺序流 Stream<String> parallelStream = names.parallelStream(); // 并行流
(2)从数组创建
String[] languages = {"Java", "Python", "C++", "JavaScript"}; Stream<String> stream = Arrays.stream(languages);
(3)使用 Stream.of()
创建
Stream<Integer> numberStream = Stream.of(1, 2, 3, 4, 5);
(4)使用 Stream.generate()
或 Stream.iterate()
// 生成 5 个随机数 Stream<Double> randomNumbers = Stream.generate(Math::random).limit(5);// 生成 1, 3, 5, 7, 9(无限流,需要 limit 限制) Stream<Integer> oddNumbers = Stream.iterate(1, n -> n + 2).limit(5);
3. Stream 常用 API 及案例
Stream 的操作分为 中间操作(Intermediate Operations) 和 终端操作(Terminal Operations)。
(1)中间操作
① filter(Predicate<T>)
:过滤元素
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); List<String> longNames = names.stream().filter(name -> name.length() > 4) // 只保留长度 >4 的名字.collect(Collectors.toList()); // 收集为 ListSystem.out.println(longNames); // [Alice, Charlie, David]
② map(Function<T, R>)
:映射转换
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); List<Integer> squares = numbers.stream().map(n -> n * n) // 计算平方.collect(Collectors.toList());System.out.println(squares); // [1, 4, 9, 16, 25]
③ flatMap(Function<T, Stream<R>>)
:扁平化流
List<List<Integer>> nestedList = Arrays.asList(Arrays.asList(1, 2, 3),Arrays.asList(4, 5, 6) );List<Integer> flatList = nestedList.stream().flatMap(List::stream) // 将多个 List 合并为一个 Stream.collect(Collectors.toList());System.out.println(flatList); // [1, 2, 3, 4, 5, 6]
④ sorted()
/ sorted(Comparator<T>)
:排序
List<String> names = Arrays.asList("Bob", "Alice", "David", "Charlie"); List<String> sortedNames = names.stream().sorted() // 自然排序(字典序).collect(Collectors.toList());System.out.println(sortedNames); // [Alice, Bob, Charlie, David]// 按长度排序 List<String> lengthSortedNames = names.stream().sorted(Comparator.comparingInt(String::length)).collect(Collectors.toList());System.out.println(lengthSortedNames); // [Bob, Alice, David, Charlie]
⑤ distinct()
:去重
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4); List<Integer> distinctNumbers = numbers.stream().distinct().collect(Collectors.toList());System.out.println(distinctNumbers); // [1, 2, 3, 4]
(2)终端操作
① forEach(Consumer<T>)
:遍历
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); names.stream().forEach(System.out::println); // 输出: // Alice // Bob // Charlie
② collect(Collector<T, A, R>)
:收集结果
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); Set<String> nameSet = names.stream().collect(Collectors.toSet());Map<String, Integer> nameLengthMap = names.stream().collect(Collectors.toMap(name -> name, // keyname -> name.length() // value));System.out.println(nameSet); // [Alice, Bob, Charlie] System.out.println(nameLengthMap); // {Alice=5, Bob=3, Charlie=7}
③ reduce(BinaryOperator<T>)
:归约
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.stream().reduce(0, (a, b) -> a + b); // 计算总和System.out.println(sum); // 15
④ count()
:计数
long count = Stream.of(1, 2, 3, 4, 5).count(); System.out.println(count); // 5
⑤ anyMatch()
/ allMatch()
/ noneMatch()
:匹配检查
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0); // 是否有偶数? boolean allPositive = numbers.stream().allMatch(n -> n > 0); // 是否全为正数? boolean noneNegative = numbers.stream().noneMatch(n -> n < 0); // 是否没有负数?System.out.println(hasEven); // true System.out.println(allPositive); // true System.out.println(noneNegative); // true
4. 综合案例
案例1:统计员工薪资
List<Employee> employees = Arrays.asList(new Employee("Alice", 5000),new Employee("Bob", 6000),new Employee("Charlie", 7000) );// 计算平均薪资 double avgSalary = employees.stream().mapToInt(Employee::getSalary) // 转为 IntStream.average().orElse(0.0);System.out.println("平均薪资:" + avgSalary);
案例2:分组统计
List<String> words = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");// 按单词长度分组 Map<Integer, List<String>> wordsByLength = words.stream().collect(Collectors.groupingBy(String::length));System.out.println(wordsByLength); // 输出:{5=[apple], 6=[banana, cherry], 4=[date], 10=[elderberry]}
案例3:并行流加速计算
List<Integer> bigList = IntStream.range(1, 10_000_000).boxed().collect(Collectors.toList());long startTime = System.currentTimeMillis(); long sum = bigList.paralleltream() // 并行流.mapToLong(Integer::longValue).sum(); long endTime = System.currentTimeMillis();System.out.println("总和:" + sum); System.out.println("耗时:" + (endTime - startTime) + "ms");
5. 总结
Stream 提供了一种高效、声明式处理集合的方式,比传统的
for
循环更简洁。中间操作(如
filter
、map
)返回新的流,终端操作(如collect
、forEach
)触发计算。并行流(
parallelStream
)可以加速大数据集处理。合理使用
map
、filter
、reduce
等操作,可以写出更优雅的代码。