0

0

Java中Stream的用法_Java中Stream的操作指南

冰火之心

冰火之心

发布时间:2025-06-29 21:15:02

|

686人浏览过

|

来源于php中文网

原创

stream是java 8引入的声明式数据处理特性,通过中间操作和终端操作简化集合处理。1. 创建方式包括:从集合调用stream()或parallelstream();2. 使用arrays.stream()转换数组;3. stream.of()直接传元素;4. generate()生成无限流需配合limit();5. iterate()创建有序无限流也需limit()。常用中间操作有filter过滤、map映射、flatmap展平嵌套结构、distinct去重、sorted排序、peek调试、limit截断、skip跳过。终端操作如foreach遍历、toarray转数组、reduce归约、collect收集结果、min/max找极值、count计数、anymatch/allmatch/nonematch判断匹配、findfirst/findany获取元素。适合使用并行流的场景包括大数据量、复杂计算、无依赖数据、cpu密集型任务且需线程安全。与传统循环相比,stream为声明式、内部迭代更简洁并支持并行处理。

Java中Stream的用法_Java中Stream的操作指南

Stream是Java 8引入的一个强大的特性,它允许你以声明式的方式处理集合数据,简化代码并提高效率。可以把它看作是数据流,你可以在上面执行各种操作,例如过滤、映射、排序等,最终得到想要的结果。

Java中Stream的用法_Java中Stream的操作指南

Stream的操作可以分为两种:中间操作和终端操作。中间操作返回一个新的Stream,允许你链式调用多个操作。终端操作则会消费Stream,产生一个结果或副作用。

Java中Stream的用法_Java中Stream的操作指南

如何创建Stream?

创建Stream的方法有很多,最常见的几种方式包括:

立即学习Java免费学习笔记(深入)”;

Java中Stream的用法_Java中Stream的操作指南
  1. 从集合创建: 这是最常用的方式,直接调用Collection接口的stream()parallelStream()方法即可。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    Stream<String> stream = names.stream(); // 创建顺序流
    Stream<String> parallelStream = names.parallelStream(); // 创建并行流
  2. 从数组创建: 使用Arrays.stream()方法可以将数组转换为Stream。

    int[] numbers = {1, 2, 3, 4, 5};
    IntStream stream = Arrays.stream(numbers);
  3. 使用Stream.of()方法: 可以直接将多个元素作为参数传递给Stream.of()方法来创建Stream。

    Stream<String> stream = Stream.of("Apple", "Banana", "Orange");
  4. 使用Stream.generate()方法: 可以使用Stream.generate()方法生成一个无限流,需要提供一个Supplier函数来生成元素。注意: 无限流需要配合limit()方法来限制流的大小,否则会无限循环。

    Stream<Double> randomStream = Stream.generate(Math::random).limit(10); // 生成10个随机数的流
  5. 使用Stream.iterate()方法: 可以使用Stream.iterate()方法生成一个有序的无限流,需要提供一个初始值和一个UnaryOperator函数来生成后续元素。同样,需要配合limit()方法来限制流的大小。

    Stream<Integer> evenNumbers = Stream.iterate(0, n -> n + 2).limit(10); // 生成10个偶数的流

Stream的常用中间操作有哪些?

中间操作会返回一个新的Stream,允许你链式调用多个操作,对数据进行转换和过滤。常见的中间操作包括:

  1. filter(Predicate predicate): 过滤Stream中的元素,只保留满足predicate条件的元素。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Anna");
    Stream<String> filteredStream = names.stream().filter(name -> name.startsWith("A")); // 过滤出以"A"开头的名字
  2. map(Function mapper): 将Stream中的每个元素映射为另一个元素,可以使用mapper函数进行转换。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    Stream<Integer> nameLengths = names.stream().map(String::length); // 将名字映射为名字的长度
  3. flatMap(Function> mapper): 将Stream中的每个元素映射为一个Stream,然后将所有Stream连接成一个Stream。这个操作通常用于处理嵌套的集合。想象一下,你有一个List>,你想把它变成一个List,flatMap就派上用场了。

    List<List<String>> nestedList = Arrays.asList(
            Arrays.asList("a", "b"),
            Arrays.asList("c", "d", "e")
    );
    Stream<String> flattenedStream = nestedList.stream().flatMap(List::stream); // 将嵌套的List展平
  4. distinct(): 去除Stream中重复的元素。

    List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3);
    Stream<Integer> distinctStream = numbers.stream().distinct(); // 去除重复的数字
  5. sorted(): 对Stream中的元素进行排序。可以传入Comparator来自定义排序规则。

    List<String> names = Arrays.asList("Charlie", "Alice", "Bob");
    Stream<String> sortedStream = names.stream().sorted(); // 默认按字母顺序排序
    Stream<String> sortedStreamByLength = names.stream().sorted(Comparator.comparingInt(String::length)); // 按名字长度排序
  6. peek(Consumer action): 对Stream中的每个元素执行action操作,但不会改变Stream的内容。这个操作通常用于调试,可以在Stream处理过程中查看元素的值。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    Stream<String> peekedStream = names.stream().peek(System.out::println); // 打印每个名字
  7. limit(long maxSize): 截断Stream,只保留前maxSize个元素。

    方正魏碑简体
    方正魏碑简体

    魏碑是指南北朝时期北朝的碑刻书法作品。现存的魏碑书体都是楷书,因此有时也把这些楷书碑刻作品称为“魏楷”。魏碑原本也称北碑,在北朝相继的各个王朝中以北魏的立国时间最长,后来就用“魏碑”来指称包括东魏、西魏、北齐和北周在内的整个北朝的碑刻书法作品。这些碑刻作品主要是以“石碑”、“墓志铭”、“ 摩崖”和“造像记”的形式存在的。 构扁方疏朗,内紧外松,多出隶意。此墓志虽属正书,行笔却不拘一格,风骨内敛,自

    下载
    Stream<Integer> numbers = Stream.iterate(1, n -> n + 1);
    Stream<Integer> limitedStream = numbers.limit(10); // 只保留前10个数字
  8. skip(long n): 跳过Stream中的前n个元素。

    Stream<Integer> numbers = Stream.iterate(1, n -> n + 1);
    Stream<Integer> skippedStream = numbers.skip(5); // 跳过前5个数字

Stream的常用终端操作有哪些?

终端操作会消费Stream,产生一个结果或副作用。常见的终端操作包括:

  1. forEach(Consumer action): 对Stream中的每个元素执行action操作。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    names.stream().forEach(System.out::println); // 打印每个名字
  2. toArray(): 将Stream中的元素转换为数组。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    String[] nameArray = names.stream().toArray(String[]::new); // 转换为String数组
  3. reduce(BinaryOperator accumulator): 将Stream中的元素归约为一个值。可以提供一个初始值,也可以不提供。

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    int sum = numbers.stream().reduce(0, Integer::sum); // 计算所有数字的和,初始值为0
    Optional<Integer> product = numbers.stream().reduce(Integer::sum); // 计算所有数字的积,没有初始值,返回Optional
  4. collect(Collector collector): 将Stream中的元素收集到集合中。可以使用Collectors类提供的各种收集器,例如toList()toSet()toMap()等。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    List<String> nameList = names.stream().collect(Collectors.toList()); // 收集到List
    Set<String> nameSet = names.stream().collect(Collectors.toSet()); // 收集到Set
    Map<String, Integer> nameMap = names.stream().collect(Collectors.toMap(name -> name, String::length)); // 收集到Map,key为名字,value为名字的长度
  5. min(Comparator comparator): 返回Stream中的最小值。需要提供一个Comparator来比较元素。

    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9);
    Optional<Integer> min = numbers.stream().min(Integer::compare); // 找到最小的数字
  6. max(Comparator comparator): 返回Stream中的最大值。需要提供一个Comparator来比较元素。

    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9);
    Optional<Integer> max = numbers.stream().max(Integer::compare); // 找到最大的数字
  7. count(): 返回Stream中元素的个数。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    long count = names.stream().count(); // 计算名字的个数
  8. anyMatch(Predicate predicate): 判断Stream中是否存在任意一个元素满足predicate条件。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    boolean anyMatch = names.stream().anyMatch(name -> name.startsWith("A")); // 是否存在以"A"开头的名字
  9. allMatch(Predicate predicate): 判断Stream中是否所有元素都满足predicate条件。

    List<String> names = Arrays.asList("Alice", "Anna", "Amy");
    boolean allMatch = names.stream().allMatch(name -> name.startsWith("A")); // 是否所有名字都以"A"开头
  10. noneMatch(Predicate predicate): 判断Stream中是否没有元素满足predicate条件。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    boolean noneMatch = names.stream().noneMatch(name -> name.startsWith("Z")); // 是否没有名字以"Z"开头
  11. findFirst(): 返回Stream中的第一个元素。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    Optional<String> first = names.stream().findFirst(); // 找到第一个名字
  12. findAny(): 返回Stream中的任意一个元素。在并行流中,findAny()的效率通常比findFirst()更高。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    Optional<String> any = names.parallelStream().findAny(); // 找到任意一个名字

什么时候应该使用并行流?

并行流可以利用多核CPU的优势,提高处理数据的效率。但是,并行流并非总是最佳选择。以下是一些需要考虑的因素:

  • 数据量: 当数据量足够大时,并行流才能体现出优势。对于小数据量,并行流的开销可能超过其带来的性能提升。
  • 操作的复杂性: 对于简单的操作,并行流的优势可能不明显。对于复杂的操作,并行流可以显著提高效率。
  • 数据之间的依赖性: 如果数据之间存在依赖性,并行流可能会导致错误的结果。
  • CPU密集型操作: 并行流更适合CPU密集型操作,例如计算、排序等。对于IO密集型操作,并行流的优势可能不明显。
  • 线程安全: 使用并行流时,需要确保操作是线程安全的。

一般来说,当数据量较大,操作比较复杂,且数据之间没有依赖性时,可以考虑使用并行流。

Stream和传统循环有什么区别?

Stream和传统循环的主要区别在于:

  • 声明式 vs 命令式: Stream采用声明式编程,你只需要描述你想做什么,而不需要关心如何实现。传统循环采用命令式编程,你需要明确地指定每一步的操作。
  • 内部迭代 vs 外部迭代: Stream采用内部迭代,由Stream API负责迭代数据。传统循环采用外部迭代,你需要自己控制迭代过程。
  • 代码简洁性: Stream可以简化代码,使代码更易读易懂。
  • 并行处理: Stream可以方便地进行并行处理,提高效率。

总的来说,Stream提供了一种更简洁、更高效的数据处理方式。在合适的场景下,使用Stream可以显著提高代码的可读性和性能。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

203

2023.11.20

php中foreach用法
php中foreach用法

本专题整合了php中foreach用法的相关介绍,阅读专题下面的文章了解更多详细教程。

245

2025.12.04

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1899

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

656

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2386

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

47

2026.01.19

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

764

2023.08.10

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

77

2025.09.05

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

4

2026.03.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

相关下载

更多

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++教程
C++教程

共115课时 | 21.3万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

微信小程序开发之API篇
微信小程序开发之API篇

共15课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号