Java Stream所有方法实例详解

 更新时间:2025年12月26日 15:31:10   作者:猩火燎猿  
该文章详细介绍了Java Stream API的创建、中间操作和终止操作,包括各种流的创建方法、常用中间操作(如filter、map、sorted等)和终止操作(如collect、forEach、reduce等),本文给大家介绍的非常详细,感兴趣的朋友一起看看吧

一、Stream 创建方法

方法说明示例
stream()从集合创建顺序流list.stream()
parallelStream()创建并行流list.parallelStream()
Stream.of()由一组元素创建流Stream.of(1, 2, 3)
Arrays.stream()由数组创建流Arrays.stream(arr)
Stream.iterate()生成无限流Stream.iterate(0, n -> n+2).limit(5)
Stream.generate()生成无限流Stream.generate(Math::random).limit(5)

二、Stream 中间操作(Intermediate Operations)

这些方法返回新的 Stream,允许链式调用。

方法说明示例
filter(Predicate)过滤元素stream.filter(x -> x > 5)
map(Function)元素映射stream.map(x -> x * 2)
flatMap(Function)展开嵌套流stream.flatMap(list -> list.stream())
distinct()去重stream.distinct()
sorted() / sorted(Comparator)排序stream.sorted() / stream.sorted(Comparator.reverseOrder())
peek(Consumer)元素遍历但不终止流stream.peek(System.out::println)
limit(long n)截取前 n 个元素stream.limit(3)
skip(long n)跳过前 n 个元素stream.skip(2)

三、Stream 终止操作(Terminal Operations)

这些方法会产生结果或副作用,流被“消费”后不可再用。

方法说明示例
forEach(Consumer)遍历元素stream.forEach(System.out::println)
collect(Collector)收集结果stream.collect(Collectors.toList())
toArray()转数组stream.toArray()
reduce(BinaryOperator)规约(聚合)stream.reduce((a, b) -> a + b)
count()计数stream.count()
anyMatch(Predicate)是否有任意元素匹配stream.anyMatch(x -> x > 5)
allMatch(Predicate)是否所有元素都匹配stream.allMatch(x -> x > 5)
noneMatch(Predicate)是否没有元素匹配stream.noneMatch(x -> x > 5)
findFirst()查找第一个元素stream.findFirst()
findAny()查找任意元素stream.findAny()
min(Comparator)最小值stream.min(Comparator.naturalOrder())
max(Comparator)最大值stream.max(Comparator.naturalOrder())

四、常用 Collector 收集器

方法说明示例
Collectors.toList()转 Liststream.collect(Collectors.toList())
Collectors.toSet()转 Setstream.collect(Collectors.toSet())
Collectors.toMap()转 Mapstream.collect(Collectors.toMap(x -> x, x -> x*2))
Collectors.joining()字符串拼接stream.collect(Collectors.joining(","))
Collectors.groupingBy()分组stream.collect(Collectors.groupingBy(x -> x%2))
Collectors.partitioningBy()分区stream.collect(Collectors.partitioningBy(x -> x > 5))
Collectors.counting()计数stream.collect(Collectors.counting())
Collectors.summingInt()求和stream.collect(Collectors.summingInt(x -> x))
Collectors.averagingInt()平均值stream.collect(Collectors.averagingInt(x -> x))
Collectors.maxBy()最大值stream.collect(Collectors.maxBy(Comparator.naturalOrder()))
Collectors.minBy()最小值stream.collect(Collectors.minBy(Comparator.naturalOrder()))

五、示例代码

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
// 过滤、映射、收集
List<Integer> result = list.stream()
    .filter(x -> x > 3)
    .map(x -> x * 2)
    .collect(Collectors.toList()); // [8, 10, 12]
// 分组
Map<Boolean, List<Integer>> partitioned = list.stream()
    .collect(Collectors.partitioningBy(x -> x % 2 == 0)); 
// 计数
long count = list.stream().filter(x -> x > 3).count();
// 求和
int sum = list.stream().reduce(0, Integer::sum);

六、补充说明

  • 中间操作是惰性求值,只有终止操作执行时才会遍历数据。
  • Stream 不能被复用,终止操作后需重新创建流。
  • 并行流(parallelStream)适用于大数据量,但需注意线程安全和性能。

七、Stream 高级用法

1. 多级分组

Map<String, Map<Integer, List<User>>> multiGroup = users.stream()
    .collect(Collectors.groupingBy(
        User::getCity,
        Collectors.groupingBy(User::getAge)
    ));

说明:先按城市分组,再按年龄分组,结果是嵌套的 Map。

2. 分区与分组的区别

  • 分区:只有两组(true/false),适合布尔条件。
  • 分组:可以有多个分组键。
Map<Boolean, List<Integer>> partition = list.stream()
    .collect(Collectors.partitioningBy(x -> x > 3));

3. 自定义收集器

可以通过Collector.of自定义收集逻辑:

Collector<Integer, ?, Set<Integer>> toCustomSet = Collector.of(
    HashSet::new,
    Set::add,
    (left, right) -> { left.addAll(right); return left; }
);
Set<Integer> set = list.stream().collect(toCustomSet);

4. 并行流

list.parallelStream()
    .filter(x -> x > 3)
    .forEach(System.out::println);

注意:并行流适合 CPU 密集型任务,IO 密集型需谨慎;操作需线程安全。

5. Optional 结合 Stream

Optional<Integer> first = list.stream().filter(x -> x > 3).findFirst();
first.ifPresent(System.out::println);

八、常见陷阱与注意点

  • 流只能用一次
    • 流操作后已关闭,不能再操作,否则抛异常。
  • 修改集合元素
    • 不建议在流操作中直接修改原集合元素,推荐返回新集合。
  • 空指针问题
    • Stream 操作前应确保集合非 null,推荐使用 Optional.ofNullable(list).orElse(Collections.emptyList()).stream()
  • 性能问题
    • distinct()sorted()等操作会增加性能消耗。
    • 并行流适合数据量大且操作无副作用的场景。

九、部分方法源码简析

1. filter

default Stream<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    return new ReferencePipeline.StatelessOp<>(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED) {
        @Override
        Sink<T> opWrapSink(int flags, Sink<T> sink) {
            return new Sink.ChainedReference<T, T>(sink) {
                @Override
                public void accept(T t) {
                    if (predicate.test(t)) downstream.accept(t);
                }
            };
        }
    };
}

说明:filter 实际上是对每个元素执行 Predicate 判断,符合条件则传递到下游。

2. map

default <R> Stream<R> map(Function<? super T, ? extends R> mapper) {
    Objects.requireNonNull(mapper);
    return new ReferencePipeline.StatelessOp<>(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED) {
        @Override
        Sink<T> opWrapSink(int flags, Sink<R> sink) {
            return new Sink.ChainedReference<T, R>(sink) {
                @Override
                public void accept(T t) {
                    downstream.accept(mapper.apply(t));
                }
            };
        }
    };
}

说明:map 通过 Function 映射每个元素,返回新的流。

十、典型业务场景举例

1. 数据去重并排序

List<String> sorted = list.stream()
    .distinct()
    .sorted()
    .collect(Collectors.toList());

2. 统计分组后的最大值

Map<String, Optional<User>> maxAgeByCity = users.stream()
    .collect(Collectors.groupingBy(
        User::getCity,
        Collectors.maxBy(Comparator.comparingInt(User::getAge))
    ));

3. 多字段分组统计

Map<String, Map<Integer, Long>> groupCount = users.stream()
    .collect(Collectors.groupingBy(
        User::getCity,
        Collectors.groupingBy(User::getAge, Collectors.counting())
    ));

4. 批量字段提取

List<String> names = users.stream()
    .map(User::getName)
    .collect(Collectors.toList());

5. Stream 处理 Map

Map<String, Integer> map = ...;
List<String> keys = map.entrySet().stream()
    .filter(e -> e.getValue() > 5)
    .map(Map.Entry::getKey)
    .collect(Collectors.toList());

十一、Stream API 性能建议

  • 尽量减少中间操作链长度,必要时合并操作。
  • 大数据量推荐并行流,但需测试线程安全和实际效率。
  • 优先使用基本类型流(IntStream、LongStream、DoubleStream)可减少装箱/拆箱开销。
  • 避免在流中写复杂逻辑,建议拆分为多个方法提高可读性。

十二、Stream 相关扩展

  • IntStream/LongStream/DoubleStream:针对基本类型的流,效率更高。
  • Collectors.toConcurrentMap:并发收集器,适合并行流。
  • Collectors.mapping:在分组或分区时对元素做映射。
  • Collectors.reducing:自定义规约操作。

十三、基本类型流详解

Java 提供了三种基本类型流,分别是 IntStreamLongStream 和 DoubleStream,它们避免了自动装箱/拆箱,提高了性能。

创建方式

IntStream intStream = IntStream.of(1, 2, 3, 4);
LongStream longStream = LongStream.range(1, 10); // [1,9]
DoubleStream doubleStream = DoubleStream.generate(Math::random).limit(5);

常用方法

方法说明示例
sum()求和intStream.sum()
average()平均值intStream.average().getAsDouble()
max() / min()最大/最小值intStream.max().getAsInt()
boxed()转换为对象流intStream.boxed()
mapToObj()基本类型流转对象流intStream.mapToObj(String::valueOf)

十四、流的收集与转换技巧

1. 转换为 Map,处理 key 重复

// value 相加
Map<String, Integer> map = list.stream()
    .collect(Collectors.toMap(
        User::getName,
        User::getScore,
        Integer::sum // 合并函数
    ));

2. 收集为不可变集合

List<String> unmodifiableList = list.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.toList(),
        Collections::unmodifiableList
    ));

3. 多字段分组

Map<String, Map<Integer, List<User>>> group = users.stream()
    .collect(Collectors.groupingBy(
        User::getCity,
        Collectors.groupingBy(User::getAge)
    ));

十五、Stream 与并发/线程安全

  • 并行流parallelStream() 会自动分片并行处理,适合无状态、无副作用的操作。
  • 线程安全收集:使用 Collectors.toConcurrentMapConcurrentHashMap 等。
ConcurrentMap<String, Integer> concurrentMap = list.parallelStream()
    .collect(Collectors.toConcurrentMap(User::getName, User::getScore));

十六、Stream 排序技巧

1. 单字段排序

list.stream()
    .sorted(Comparator.comparing(User::getAge))
    .collect(Collectors.toList());

2. 多字段排序

list.stream()
    .sorted(Comparator.comparing(User::getAge)
        .thenComparing(User::getName))
    .collect(Collectors.toList());

3. 逆序排序

list.stream()
    .sorted(Comparator.comparing(User::getAge).reversed())
    .collect(Collectors.toList());

十七、Stream 实用代码片段

1. 找出重复元素

Set<Integer> seen = new HashSet<>();
Set<Integer> duplicates = list.stream()
    .filter(n -> !seen.add(n))
    .collect(Collectors.toSet());

2. 分页功能

int page = 2, size = 5;
List<Integer> pageList = list.stream()
    .skip((page - 1) * size)
    .limit(size)
    .collect(Collectors.toList());

3. 按条件统计数量

long count = list.stream().filter(x -> x > 10).count();

4. 合并两个 List 并去重

List<Integer> merged = Stream.concat(list1.stream(), list2.stream())
    .distinct()
    .collect(Collectors.toList());

十八、常见问题与解决方案

1. Stream 只用一次

Stream<String> s = list.stream();
s.forEach(System.out::println);
// s.forEach(...) // 抛异常,不可再用

解决:重新创建流。

2. NullPointerException

集合为 null 时不能直接调用 stream()

List<String> safeList = Optional.ofNullable(list)
    .orElse(Collections.emptyList());
safeList.stream()...

3. 性能瓶颈

  • 避免在流操作中写复杂逻辑,拆分方法。
  • 并行流适合数据量大且操作无副作用,需实际测试。

十九、Collectors 的扩展用法

1. mapping

分组后对分组内元素做映射:

Map<String, List<String>> nameGroup = users.stream()
    .collect(Collectors.groupingBy(
        User::getCity,
        Collectors.mapping(User::getName, Collectors.toList())
    ));

2. reducing

自定义聚合:

int totalScore = users.stream()
    .collect(Collectors.reducing(0, User::getScore, Integer::sum));

二十、Stream 处理嵌套集合

List<List<Integer>> nested = Arrays.asList(
    Arrays.asList(1,2),
    Arrays.asList(3,4)
);
List<Integer> flat = nested.stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toList());

二十一、Stream API 新增方法(Java 9+)

如果你用的是 Java 9 及以上,还可以用:

  • takeWhile(Predicate):从头开始,遇到不满足条件就停止。
  • dropWhile(Predicate):从头开始,遇到不满足条件后开始收集。
  • Stream.ofNullable(obj):对象为 null 返回空流,否则返回单元素流。
Stream.ofNullable(null).count(); // 0
Stream.ofNullable("abc").count(); // 1

二十二、Stream 与 Lambda 表达式最佳实践

  • 保持流操作简洁,避免嵌套 lambda 过多。
  • 推荐将复杂逻辑提取为方法引用或单独方法。
  • 用注释说明复杂的流链。

总结

Java Stream 提供了丰富的 API,适合处理集合的各种操作,包括过滤、映射、分组、聚合、排序、去重等。掌握 Stream 可以极大提升 Java 代码的简洁性和表现力。

到此这篇关于Java Stream所有方法实例详解的文章就介绍到这了,更多相关Java Stream所有方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • spring security中的csrf防御原理(跨域请求伪造)

    spring security中的csrf防御原理(跨域请求伪造)

    这篇文章主要介绍了spring security中的csrf防御机制原理解析(跨域请求伪造),本文通过实例代码详解的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-12-12
  • SpringBoot项目中filter的两种使用详解

    SpringBoot项目中filter的两种使用详解

    文章介绍了两种方式在Spring Boot中创建和配置过滤器:使用`@WebFilter`注解和`@ServletComponentScan`注解,以及通过`@Bean`注解自定义过滤器并加载到IOC容器,通过测试启动项目并访问指定URL,可以查看控制台打印的过滤器执行顺序结果
    2025-10-10
  • Spring框架对于Bean的管理详解

    Spring框架对于Bean的管理详解

    在实际开发中,我们往往要用到Spring容器为我们提供的诸多资源,例如想要获取到容器中的配置、获取到容器中的Bean等等。本文为大家详细讲讲工具类如何获取到Spring容器中的Bean,需要的可以参考一下
    2022-07-07
  • java实现DWG文件转图片的示例代码

    java实现DWG文件转图片的示例代码

    在Java中将DWG文件转换为图片是一个常见的需求,下面将详细介绍如何使用Java将DWG文件转换为图片,并探讨几个流行的解决方案,大家可以根据需要进行选择
    2025-10-10
  • eclipse中没有SERVER的解决办法(超详细)

    eclipse中没有SERVER的解决办法(超详细)

    使用eclipse进行tomcat配置时,经常会发现一个重要的问题就是打开eclipse之后没有了server选项,所以本给大家详细介绍了eclipse中没有SERVER的解决办法,文中有详细的图文讲解,需要的朋友可以参考下
    2023-12-12
  • Java实现拓扑排序算法的示例代码

    Java实现拓扑排序算法的示例代码

    在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。本文将为大家讲讲拓扑排序算法的原理及实现,需要的可以参考一下
    2022-07-07
  • spring-security关闭登录框的实现示例

    spring-security关闭登录框的实现示例

    这篇文章主要介绍了spring-security关闭登录框的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • 完美解决Spring Boot前端的Access-Control-Allow-Origin跨域问题

    完美解决Spring Boot前端的Access-Control-Allow-Origin跨域问题

    这篇文章主要介绍了完美解决Spring Boot前端的Access-Control-Allow-Origin跨域问题,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • java easyPOI实现导出一对多数据

    java easyPOI实现导出一对多数据

    这篇文章主要为大家详细介绍了java如何利用easyPOI实现导出一对多数据,并且可以设置边框、字体和字体大小,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-12-12
  • Spring中@Transactional注解的使用详解

    Spring中@Transactional注解的使用详解

    @Transactional注解是Spring提供的一种声明式事务管理方式,这篇文章主要为大家详细介绍了@Transactional注解的原理分析及使用,需要的可以参考一下
    2023-05-05

最新评论