Java集合中Stream流的使用

前言

Java 8 引入了 Stream API,它是一种用于处理集合(Collection)数据的强大工具。Stream 不是数据结构,而是对数据源进行操作的一种方式,支持声明式、函数式的操作,如过滤、映射、排序等。

Stream 操作分为中间操作和终端操作:

  • 中间操作(Intermediate operations):返回一个 Stream,可以链式调用。
  • 终端操作(Terminal operations):触发实际计算,返回非 Stream 类型的结果。

获取 Stream 的方式

常见的创建 Stream 的方法如下:

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

// 从数组创建
int[] arr = {1, 2, 3};
IntStream intStream = Arrays.stream(arr);

// 使用 Stream.of 创建
Stream<String> stream = Stream.of("a", "b", "c");

// 无限流(generate / iterate)
Stream<Integer> infiniteStream = Stream.generate(() -> 1);
Stream<Integer> iterateStream = Stream.iterate(0, n -> n + 2);

Stream 的常用操作

filter

用于过滤符合条件的数据:

java 复制代码
List<String> filtered = list.stream()
    .filter(s -> s.startsWith("J"))
    .toList();

map

将每个元素映射成另一个对象:

java 复制代码
List<String> upperCase = list.stream()
    .map(String::toUpperCase)
    .toList();

sorted

对流中的元素进行排序:

java 复制代码
List<String> sorted = list.stream()
    .sorted()
    .toList();

也可以自定义排序规则

java 复制代码
.sorted((s1, s2) -> s2.compareTo(s1))

或者使用 Comparator:

java 复制代码
.sorted(Comparator.reverseOrder())

limit / skip

限制流的大小或跳过前 N 个元素:

java 复制代码
List<String> limited = list.stream()
    .limit(2)
    .toList();

List<String> skipped = list.stream()
    .skip(2)
    .toList();

distinct

去重,基于 equals() 方法判断重复项:

java 复制代码
List<String> unique = list.stream()
    .distinct()
    .toList();

forEach

遍历流中的每个元素:

java 复制代码
list.stream()
    .forEach(System.out::println);

collect

收集流的结果到容器中,常配合 Collectors 使用:

java 复制代码
List<String> filteredList = list.stream()
    .filter(s -> s.length() > 3)
    .collect(Collectors.toList());

String joined = list.stream()
    .collect(Collectors.joining(", "));

reduce

归约操作,合并流中的元素为一个结果:

java 复制代码
Optional<String> reduced = list.stream()
    .reduce((s1, s2) -> s1 + "-" + s2);

也可以提供初始值:

java 复制代码
String result = list.stream()
    .reduce("start", (acc, s) -> acc + "-" + s);

并行流(Parallel Stream)

使用并行流可以提高大数据量下的处理效率:

java 复制代码
List<String> parallelResult = list.parallelStream()
    .filter(s -> s.startsWith("A"))
    .toList();

需要注意线程安全问题和是否适合并行处理。

注意事项

  • Stream 只能被消费一次,再次使用会抛出异常。
  • 中间操作是惰性求值的,只有遇到终端操作才会真正执行。
  • 避免在流中修改外部变量,容易引发并发问题。
  • 适当使用并行流,不是所有情况都适用。
  • 注意空指针异常,尤其是在处理集合时。

总结

Stream API 极大地简化了对集合的操作,使得代码更简洁、可读性更高。通过链式调用,我们可以清晰地表达数据处理逻辑。但也要注意其性能特性和使用场景,合理选择是否使用 Stream 或传统循环。

相关推荐
IT枫斗者枫哥8 分钟前
CompletableFuture失败后返回空列表:异常没了,业务含义也变了
java·后端
知识搬运临时工19 分钟前
一个模板把 AEM 拖进 Full GC 死亡螺旋:300% CPU、7 GB 堆、310 万行堆栈
java·aws
熊猫钓鱼>_>22 分钟前
鸿蒙 PC 三方库适配复盘:libfvad 1.0 —— 把 WebRTC VAD 做成能装进采集链路的静态库
服务器·开发语言·华为·harmonyos·openharmony·适配·鸿蒙pc
用户4329359280523 分钟前
CoAP还是MQTT:1万只Cat.1水表三个月带宽续航实测
java
知守观33 分钟前
多模块架构演进:横向分层 vs 纵向领域,13 个真实项目的切分对照
java·后端·微服务
Ai-_Man34 分钟前
Coze扣子还是不可以导出左侧所有对话,只能点进去单条内容导出,方法不对吗?
开发语言·人工智能·ai·小程序·1024程序员节
raindayinrain43 分钟前
c++设计模式
开发语言·c++·设计模式
Java成神之路-1 小时前
Java String 为什么不可变?和 HashMap 到底有什么关系?
java
hiahiahia1231 小时前
Streaming Model Output
开发语言·前端
paopaokaka_luck1 小时前
基于springboot+vue的益暖微光公益服务平台(DeepSeek公益助手、善款信息追溯、志愿服务积分闭环、ECharts运营分析、活动状态自动流转)
java·前端·javascript·spring boot·mysql·架构·echarts