0

0

Java中如何用Stream对集合进行过滤和映射

冰火之心

冰火之心

发布时间:2025-06-12 16:42:01

|

551人浏览过

|

来源于php中文网

原创

java stream 是一种声明式处理集合的方式,通过操作链实现数据过滤、转换等。其核心思想是将数据源如 list、set 转换为 stream,接着使用 filter() 方法接收 predicate 接口以判断元素是否保留来过滤数据,如用 n -> n > 10 过滤出大于 10 的数字;随后可调用 map() 方法接收 function 接口以转换元素,如 string::touppercase 将字符串转为大写;这些中间操作具备延迟执行特性,只有终端操作如 collect()、foreach()、sum() 等被调用时才执行,且可并行处理,通过 parallelstream() 分解任务提升性能,但需评估线程开销;此外,stream 只能使用一次,消耗后需重新创建;异常处理可通过 try-catch 捕获或 optional 类型安全处理 null 值,确保流操作的健壮性。

Java中如何用Stream对集合进行过滤和映射

Java Stream提供了一种声明式的方式来处理集合数据,核心在于通过一系列操作链,实现数据的过滤、转换等。简单来说,就是把集合变成一个“流”,然后像流水线一样加工它。

Java中如何用Stream对集合进行过滤和映射

解决方案

Java中如何用Stream对集合进行过滤和映射

Java Stream API 允许你以函数式风格对集合进行过滤和映射。其核心思想是将数据源(如 List、Set 等)转换为 Stream,然后应用一系列中间操作(如 filter、map)来转换数据,最后通过终端操作(如 collect、forEach)来产生结果。

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

Java中如何用Stream对集合进行过滤和映射

如何使用 Stream 进行过滤?

过滤操作 filter() 接收一个 Predicate 函数式接口,该接口定义了一个 test() 方法,用于判断元素是否应该被包含在结果流中。

例如,假设你有一个整数列表,想要过滤出所有大于 10 的数字:

List<Integer> numbers = Arrays.asList(1, 5, 12, 8, 15, 3);

List<Integer> filteredNumbers = numbers.stream()
                                        .filter(n -> n > 10)
                                        .collect(Collectors.toList());

System.out.println(filteredNumbers); // 输出: [12, 15]

这里,n -> n > 10 就是一个 Predicate 表达式,它判断数字 n 是否大于 10。collect(Collectors.toList()) 则是将过滤后的 Stream 转换回 List。

如何使用 Stream 进行映射?

映射操作 map() 接收一个 Function 函数式接口,该接口定义了一个 apply() 方法,用于将一个元素转换为另一个元素。

例如,假设你有一个字符串列表,想要将每个字符串转换为大写:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

List<String> upperCaseNames = names.stream()
                                   .map(String::toUpperCase)
                                   .collect(Collectors.toList());

System.out.println(upperCaseNames); // 输出: [ALICE, BOB, CHARLIE]

String::toUpperCase 是一个方法引用,它等价于 s -> s.toUpperCase(),将字符串 s 转换为大写。

如何同时进行过滤和映射?

你可以将 filter()map() 操作链式调用,先过滤再映射,或者先映射再过滤,取决于你的需求。

例如,假设你有一个 Person 对象列表,想要获取所有年龄大于 20 岁的人的名字,并将名字转换为大写:

class Person {
    String name;
    int age;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

List<Person> people = Arrays.asList(
    new Person("Alice", 25),
    new Person("Bob", 18),
    new Person("Charlie", 30)
);

List<String> upperCaseNames = people.stream()
                                     .filter(p -> p.getAge() > 20)
                                     .map(Person::getName)
                                     .map(String::toUpperCase)
                                     .collect(Collectors.toList());

System.out.println(upperCaseNames); // 输出: [ALICE, CHARLIE]

这里,我们先使用 filter() 过滤出年龄大于 20 岁的人,然后使用 map() 获取他们的名字,再使用 map() 将名字转换为大写。

Stream 的延迟执行特性是什么?

Stream 的一个重要特性是延迟执行(Lazy Evaluation)。中间操作(如 filter()map())不会立即执行,而是会等到终端操作(如 collect())被调用时才一起执行。

AI Note
AI Note

AI Note 助手,像贴心女仆一样助力你的笔记!智能总结内容,精确划重点,提供专业建议,让学习与工作更高效。让你的笔记更清晰、有条理,知识尽在眼前!

下载

这种延迟执行的特性可以提高性能,因为 Stream 可以避免不必要的计算。例如,如果你的 Stream 只需要处理前几个元素,那么 Stream 可以只计算前几个元素,而不需要计算整个集合。

Stream 可以并行处理吗?

Stream 可以通过调用 parallelStream() 方法来并行处理。并行处理可以将任务分解成多个子任务,并在多个线程上同时执行,从而提高处理速度。

例如,假设你想要计算一个大型数字列表中所有大于 10 的数字的总和:

List<Integer> numbers = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
    numbers.add(i);
}

int sum = numbers.parallelStream()
                 .filter(n -> n > 10)
                 .mapToInt(Integer::intValue)
                 .sum();

System.out.println(sum);

这里,我们使用 parallelStream() 创建一个并行 Stream,然后使用 filter() 过滤出大于 10 的数字,再使用 mapToInt() 将 Integer 对象转换为 int 类型,最后使用 sum() 计算总和。

需要注意的是,并行处理并非总是能提高性能。如果任务过于简单,或者数据量太小,并行处理可能会因为线程切换的开销而降低性能。因此,在使用并行 Stream 之前,需要仔细评估其性能影响。

Stream 只能使用一次吗?

是的,Stream 只能使用一次。一旦你对 Stream 执行了终端操作,Stream 就被“消耗”掉了,不能再次使用。如果你需要再次使用相同的数据,你需要重新创建一个新的 Stream。这其实也符合“流”的概念,用完就没了。

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

除了 collect()forEach()sum() 之外,Stream 还有很多其他常用的终端操作,例如:

  • count(): 统计 Stream 中元素的数量。
  • min(): 找出 Stream 中最小的元素。
  • max(): 找出 Stream 中最大的元素。
  • findFirst(): 找出 Stream 中第一个元素。
  • findAny(): 找出 Stream 中任意一个元素。
  • anyMatch(): 判断 Stream 中是否存在至少一个元素满足指定条件。
  • allMatch(): 判断 Stream 中是否所有元素都满足指定条件。
  • noneMatch(): 判断 Stream 中是否没有任何元素满足指定条件。
  • reduce(): 将 Stream 中的元素聚合为一个结果。

这些终端操作可以满足各种不同的需求,你可以根据实际情况选择合适的终端操作。

Stream 的异常处理应该如何进行?

在 Stream 操作中,如果某个操作抛出异常,整个 Stream 流程将会中断。为了避免这种情况,你需要对 Stream 操作进行异常处理。

一种常见的做法是使用 try-catch 块来捕获异常,并在 catch 块中进行处理。例如:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", null);

names.stream()
     .map(name -> {
         try {
             return name.toUpperCase();
         } catch (NullPointerException e) {
             System.err.println("遇到空指针异常: " + e.getMessage());
             return null; // 或者返回一个默认值
         }
     })
     .filter(Objects::nonNull) // 过滤掉 null 值
     .forEach(System.out::println);

在这个例子中,我们使用 try-catch 块来捕获 NullPointerException 异常,并在 catch 块中打印错误信息,然后返回 null 值。最后,我们使用 filter(Objects::nonNull) 来过滤掉 null 值。

另一种做法是使用 Optional 来处理可能为空的值。例如:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", null);

names.stream()
     .map(name -> Optional.ofNullable(name)
                          .map(String::toUpperCase)
                          .orElse(null))
     .filter(Objects::nonNull)
     .forEach(System.out::println);

在这个例子中,我们使用 Optional.ofNullable(name)name 转换为 Optional 对象。如果 namenull,则 Optional 对象为空。然后,我们使用 map(String::toUpperCase)Optional 对象中的字符串转换为大写。如果 Optional 对象为空,则 map() 方法不会执行。最后,我们使用 orElse(null) 来返回 Optional 对象中的值,如果 Optional 对象为空,则返回 null

总而言之,Java Stream 是一种强大的工具,可以让你以简洁、高效的方式处理集合数据。掌握 Stream API 的使用方法,可以大大提高你的编程效率。

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

通义千问
通义千问

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

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1010

2023.08.02

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

254

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1089

2024.03.01

counta和count的区别
counta和count的区别

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

203

2023.11.20

php中foreach用法
php中foreach用法

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

265

2025.12.04

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

760

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

220

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1565

2023.10.24

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

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

4

2026.03.10

热门下载

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

精品课程

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

共23课时 | 4.3万人学习

C# 教程
C# 教程

共94课时 | 11.1万人学习

Java 教程
Java 教程

共578课时 | 80.3万人学习

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

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