Java Stream 流式编程

Java 8 引入的 Stream API 是一种 声明式 的数据处理方式,用于处理集合、数组等数据源。它将数据处理操作(如过滤、映射、排序、聚合)以链式方式组织,简化了集合的处理逻辑,提升了代码的可读性和可维护性。


一、Stream 的核心概念

1. 流(Stream)

  • 流是一组元素的序列,支持顺序或并行处理。
  • 流不是集合 ,它本身不存储数据,而是对数据源(如 ListSetMap、数组等)进行操作。
  • 流只能被消费一次,一旦执行终端操作,流就关闭,不能再使用。

2. 操作类型

Stream 的操作分为两类:

操作类型 说明 常见方法
中间操作(Intermediate Operations) 返回一个新的流,可以链式调用 filter()map()sorted()distinct()
终端操作(Terminal Operations) 返回非流的结果(如 Listintvoid collect()forEach()count()findFirst()

二、Stream 的处理流程

java 复制代码
List<String> result = list.stream()
.filter(s -> s.length() > 3)// 中间操作
.map(String::toUpperCase)// 中间操作
.sorted()// 中间操作
.collect(Collectors.toList());// 终端操作

流程图:

复制代码
数据源(如 List) → 流 → 中间操作 → 中间操作 → ... → 终端操作 → 结果

三、常用操作与案例

1. 创建流(Stream)

java 复制代码
// 从集合创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();

// 从数组创建
String[] arr = {"x", "y", "z"};
Stream<String> stream2 = Arrays.stream(arr);

// 生成无限流
Stream<Integer> infiniteStream = Stream.iterate(1, n -> n + 1);

2. 中间操作

(1) filter(Predicate):过滤符合条件的元素
java 复制代码
List<String> filtered = list.stream()
.filter(s -> s.length() > 3)
.collect(Collectors.toList());
(2) map(Function):将元素映射为其他类型
java 复制代码
List<Integer> lengths = list.stream()
.map(String::length)
.collect(Collectors.toList());
(3) sorted(Comparator):排序
java 复制代码
List<String> sorted = list.stream()
.sorted(Comparator.reverseOrder()) // 降序
.collect(Collectors.toList());
(4) distinct():去重
java 复制代码
List<String> unique = list.stream()
.distinct()
.collect(Collectors.toList());
(5) limit(long) / skip(long):截取或跳过
java 复制代码
List<String> limited = list.stream()
.limit(2) // 取前2个元素
.collect(Collectors.toList());

3. 终端操作

(1) collect(Collector):收集结果(最常用)
java 复制代码
List<String> listResult = stream.collect(Collectors.toList());
Set<String> setResult = stream.collect(Collectors.toSet());
Map<String, Integer> mapResult = stream.collect(Collectors.toMap(...));
(2) forEach(Consumer):遍历
java 复制代码
stream.forEach(System.out::println);
(3) count():统计元素数量
java 复制代码
long count = stream.count();
(4) findFirst() / findAny():查找第一个或任意元素
java 复制代码
Optional<String> first = stream.findFirst();
(5) anyMatch() / allMatch() / noneMatch():匹配判断
java 复制代码
boolean hasLong = stream.anyMatch(s -> s.length() > 3);
(6) reduce():归约操作(如求和、最大值)
java 复制代码
int sum = stream.mapToInt(Integer::intValue).sum();
Optional<Integer> max = stream.reduce(Integer::max);

四、高级用法与案例

1. 分组(Grouping By)

java 复制代码
Map<String, List<User>> usersByGender = userList.stream()
.collect(Collectors.groupingBy(User::getGender));

2. 分区(Partitioning By)

java 复制代码
Map<Boolean, List<User>> activeUsers = userList.stream()
.collect(Collectors.partitioningBy(User::isActive));

3. 统计(Summarizing)

java 复制代码
IntSummaryStatistics stats = userList.stream()
.collect(Collectors.summarizingInt(User::getAge));

4. 多级分组

java 复制代码
Map<String, Map<String, List<User>>> usersByGenderAndCity = userList.stream()
.collect(Collectors.groupingBy(User::getGender,
Collectors.groupingBy(User::getCity)));

5. 拼接字符串(Joining)

java 复制代码
String names = userList.stream()
.map(User::getName)
.collect(Collectors.joining(", ")); // "Alice, Bob, Charlie"

五、并行流(Parallel Stream)

并行流利用多核 CPU 加速计算,适用于大数据量处理:

java 复制代码
List<String> result = list.parallelStream()
.map(String::toUpperCase)
.collect(Collectors.toList());

⚠️ 注意:并行流不保证顺序,且对线程安全要求较高。


六、完整示例代码

java 复制代码
import java.util.*;
import java.util.stream.Collectors;

class User {
private String name;
private int age;
private String gender;

public User(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}

public String getName() { return name; }
public int getAge() { return age; }
public String getGender() { return gender; }

@Override
public String toString() {
return name;
}
}

public class StreamDemo {
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("Alice", 25, "Female"),
new User("Bob", 30, "Male"),
new User("Charlie", 22, "Male"),
new User("Diana", 28, "Female")
);

// 案例1:过滤 + 映射 + 收集
List<String> maleNames = users.stream()
.filter(u -> "Male".equals(u.getGender()))
.map(User::getName)
.collect(Collectors.toList());
System.out.println("Male names: " + maleNames);

// 案例2:分组 + 统计
Map<String, Double> avgAgeByGender = users.stream()
.collect(Collectors.groupingBy(User::getGender,
Collectors.averagingInt(User::getAge)));
System.out.println("Average age by gender: " + avgAgeByGender);

// 案例3:并行流求和
int totalAge = users.parallelStream()
.mapToInt(User::getAge)
.sum();
System.out.println("Total age: " + totalAge);

// 案例4:查找最年长用户
Optional<User> oldest = users.stream()
.max(Comparator.comparing(User::getAge));
System.out.println("Oldest user: " + oldest.orElse(null));
}
}

七、Stream 的优势

优势 说明
声明式语法 用链式调用表达逻辑,代码更简洁
函数式编程支持 使用 Lambda 表达式简化操作
链式操作 支持中间操作的灵活组合
并行处理 利用多核 CPU 提升性能
内置丰富的操作 提供过滤、映射、分组、统计等工具

八、注意事项

  1. 流只能消费一次:终端操作后,流关闭,再次使用会抛异常。
  2. 避免副作用 :中间操作(如 forEach)不应修改外部状态。
  3. 性能权衡:小数据集使用普通循环更高效,大数据集使用并行流。
  4. 线程安全:并行流操作需确保数据和操作是线程安全的。

九、总结

Java Stream 是一种 声明式 的数据处理工具,通过链式操作简化集合处理,提升了代码的可读性和可维护性。结合 CollectorsOptionalComparator 等工具,可以轻松实现过滤、映射、分组、统计等复杂操作。合理使用 Stream 能显著提高开发效率和代码质量。

相关推荐
Penge6662 小时前
Go 接口编译期断言
后端
我是一颗柠檬2 小时前
【MySQL全面教学】MySQL面试高频考点汇总Day15(2026年)
数据库·后端·mysql·面试
橙淮3 小时前
并发编程(六)
java·jvm
拽着尾巴的鱼儿3 小时前
springboot openfeign 自定义feign 接口重试机制
java·spring boot·后端
白露与泡影3 小时前
2026大厂Java面试题大全!牛客网最新版
java·开发语言
Ceelog3 小时前
久坐党自救指南:屏幕前 8 小时,身体到底在经历什么
前端·后端
EntyIU4 小时前
JVM内存与GC笔记
java·jvm·笔记
XS0301064 小时前
并发编程 六
java·后端
yaoxin5211234 小时前
419. 现代 Java IO 最佳实践 - 写入文本文件
java·windows·python
雪宫街道4 小时前
synchronized 锁的范围:对象锁、类锁与代码块锁
java·jvm·后端·面试