Java Stream 过滤
最后修改于 2025 年 5 月 25 日
在本文中,我们将探讨如何使用过滤操作有效地过滤 Java 流。过滤是函数式编程中的一项基本技术,可帮助优化数据集,提取相关信息并简化 Java 流中的数据处理。
Java Stream 表示来自数据源的一系列元素,支持各种聚合操作,例如过滤、映射、归约和排序。与集合不同,流不会永久存储元素;相反,它们按需处理元素,使其对于大型数据集非常有效。Java 流可以对集合、数组、I/O 资源和其他来源进行操作,从而提供了一种函数式的数据操作方法。
流聚合操作类似于 SQL 查询,允许开发人员以最少的代码执行复杂的数据转换。通过函数式编程原则,流可以实现以下操作:
- 过滤: 根据条件选择元素。
- 映射: 将元素从一种形式转换为另一种形式。
- 归约: 聚合元素以计算汇总结果。
- 匹配: 检查元素是否满足特定标准。
- 排序: 有效地对元素进行排序。
Java 流的关键优势之一是它们能够链接多个操作,从而生成简洁、可读且高效的代码。与依赖外部迭代的传统集合不同,Java 流利用内部迭代,将执行控制委托给运行时以进行优化处理。
filter 方法
Java Stream 的 filter
方法是一个中间操作,旨在选择满足指定条件的元素。它接受一个谓词函数,该函数评估每个元素并返回一个布尔值,指示该元素是否应包含在最终流中。
在处理大型数据集时,此方法特别有用,它允许开发人员优化和提取相关数据,而无需修改原始集合。
filter
方法可以与其他流操作组合使用,以进行复杂的数据处理,从而使 Java 流成为现代应用程序开发的强大工具。
按字符串长度过滤
以下示例过滤字符串列表。
void main() { List<String> words = List.of("pen", "custom", "orphanage", "forest", "bubble", "butterfly"); List<String> result = words.stream().filter(word -> word.length() > 5).toList(); result.forEach(System.out::println); }
我们有一个单词列表。我们过滤该列表,仅包含长度大于 5 的字符串。
List<String> result = words.stream().filter(word -> word.length() > 5).toList();
使用 stream
方法,我们从字符串列表创建一个 Java Stream。在此流上,我们应用 filter
方法。 filter
方法接受一个匿名函数,该函数对于流中所有长度大于 5 的元素返回布尔值 true。
result.forEach(System.out::println);
我们使用 forEach
方法遍历结果,并将所有元素打印到控制台。
$ java Main.java custom orphanage forest bubble butterfly
过滤 null 值
下一个示例过滤掉 null
值。
void main() { List<String> words = new ArrayList<>(); words.add("cup"); words.add(null); words.add("forest"); words.add("sky"); words.add("book"); words.add(null); words.add("theatre"); List<String> result = words.stream().filter(Objects::nonNull).toList(); System.out.println(result); }
我们有一个单词列表。通过 Stream 过滤操作,我们创建一个新列表,其中丢弃了 null
值。
List<String> result = words.stream().filter(Objects::nonNull).toList();
在 lambda 表达式的主体中,我们检查该值是否不是 null
。 toList
方法是一个终端操作,它从过滤后的流中创建一个列表。
多个过滤操作
可以在流上应用多个过滤操作。
void main() { int[] inums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; IntConsumer icons = i -> System.out.print(i + " "); Arrays.stream(inums).filter(e -> e < 6 || e > 10) .filter(e -> e % 2 == 0).forEach(icons); }
在此示例中,我们在整数流上应用多个过滤操作。
int[] inums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
我们有一个整数值数组。
IntConsumer icons = i -> System.out.print(i + " ");
IntConsumer
是一个函数式接口,它接受一个整数值并对其执行操作。在这种情况下,它将整数值打印到控制台。
Arrays.stream(inums).filter(e -> e < 6 || e > 10) .filter(e -> e % 2 == 0).forEach(icons);
使用 Arrays.stream
方法从数组创建一个流。 执行多个过滤操作。
过滤对象
下一个示例显示如何过滤对象。
void main() { List<User> persons = List.of( new User("Jack", "jack234@gmail.com"), new User("Peter", "pete2@post.com"), new User("Lucy", "lucy17@gmail.com"), new User("Robert", "bob56@post.com"), new User("Martin", "mato4@imail.com") ); List<User> result = persons.stream() .filter(person -> person.email().matches(".*post\\.com")) .toList(); result.forEach(p -> System.out.println(p.name())); } record User(String name, String email) { }
该示例创建一个 User
对象流。 它过滤掉那些与特定正则表达式匹配的对象。
List<User> result = persons.stream() .filter(person -> person.email().matches(".*post\\.com")) .toList();
在过滤谓词中,我们选择与 .*post\\.com
模式匹配的电子邮件。
按年龄过滤用户
下一个示例按年龄过滤用户。 我们使用 Period
类根据用户的出生日期计算用户的年龄。
void main() { List<User> users = List.of( new User("John", "Doe", "1990-01-01"), new User("Jane", "Doe", "1985-05-15"), new User("Alice", "Smith", "2000-12-31"), new User("Paul", "Anka", "1965-11-04"), new User("Bob", "Brown", "1995-07-20"), new User("Charlie", "Johnson", "1980-03-10"), new User("Diana", "Prince", "1992-11-11") ); users.stream() .filter(user -> user.age() > 40) .forEach(user -> System.out.printf( "%s %s is %d years old%n", user.firstName(), user.lastName(), user.age())); } record User(String firstName, String lastName, String dateOfBirth) { int age() { return Period.between( LocalDate.parse(dateOfBirth), LocalDate.now()).getYears(); } }
filter
方法用于选择年龄大于 40 岁的用户。
$ java Main.java Paul Anka is 59 years old Charlie Johnson is 45 years old
按键过滤映射
在以下示例中,我们按键过滤映射。 使用 Map.Entry
接口的 getKey
方法检索键。
void main() { Map<String, String> hmap = new HashMap<>(); hmap.put("de", "Germany"); hmap.put("hu", "Hungary"); hmap.put("sk", "Slovakia"); hmap.put("si", "Slovenia"); hmap.put("so", "Somalia"); hmap.put("us", "United States"); hmap.put("ru", "Russia"); hmap.entrySet().stream().filter(map -> map.getKey().startsWith("s")) .forEach(System.out::println); }
该示例过滤以字母 s 开头的域名。 我们使用 getKey
方法检索映射条目的键,并使用 startsWith
方法检查它是否以字母 s
开头。
按值过滤映射
在以下示例中,我们按值过滤映射。 使用 Map.Entry
接口的 getValue
方法检索值。
void main() { Map<String, String> countries = new HashMap<>(); countries.put("de", "Germany"); countries.put("hu", "Hungary"); countries.put("sk", "Slovakia"); countries.put("si", "Slovenia"); countries.put("so", "Somalia"); countries.put("us", "United States"); countries.put("ru", "Russia"); countries.entrySet().stream().filter(country -> country.getValue().equals("Slovakia") || country.getValue().equals("Slovenia")) .forEach(System.out::println); }
在此示例中,我们从映射中过滤掉两个国家/地区。 我们使用 getValue
方法检索映射条目的值,并使用 equals
方法检查它是否等于 "Slovakia" 或 "Slovenia" 。
来源
在本文中,我们已经研究了 Java Stream 过滤操作。
作者
列出所有Java教程。