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 能显著提高开发效率和代码质量。

相关推荐
武子康13 分钟前
大数据-238 离线数仓 - 广告业务 Hive分析实战:ADS 点击率、购买率与 Top100 排名避坑
大数据·后端·apache hive
Seven971 小时前
剑指offer-79、最⻓不含重复字符的⼦字符串
java
Victor3561 小时前
MongoDB(23) 如何使用条件查询文档?
后端
摸鱼的春哥1 小时前
Agent教程15:认识LangChain,Agent框架的王(上)
前端·javascript·后端
Victor3561 小时前
MongoDB(22)如何批量插入文档?
后端
追逐时光者8 小时前
一款使用 C# 编写专为 Windows 11 打造的文件资源管理器增强工具!
后端·.net
风象南9 小时前
普通人用AI加持赚到的第一个100块
人工智能·后端
皮皮林55110 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java
冰_河11 小时前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化