首页 > Java > 正文

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

冰火之心
发布: 2025-06-12 16:42:01
原创
548人浏览过

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制作口播视频

开拍 289
查看详情 开拍

这种延迟执行的特性可以提高性能,因为 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 的使用方法,可以大大提高你的编程效率。

以上就是Java中如何用Stream对集合进行过滤和映射的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

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