ZetCode

Java Stream 匹配

最后修改于 2025 年 5 月 25 日

本文演示了如何使用 Java Stream 的匹配操作:anyMatch、allMatch 和 noneMatch 来检查流中的条件。

Stream 匹配操作是终端操作,用于检查流中的元素是否满足特定条件。 它们返回一个布尔值,并且具有短路特性(可能提前终止,而无需处理所有元素)。

基本匹配操作

这三个匹配方法具有相似的签名

boolean anyMatch(Predicate<? super T> predicate)
boolean allMatch(Predicate<? super T> predicate)
boolean noneMatch(Predicate<? super T> predicate)

anyMatch 如果任何元素匹配谓词则返回 true。 allMatch 如果所有元素都匹配则返回 true。 noneMatch 如果没有元素匹配则返回 true。

anyMatch - 检查是否存在

下一个示例使用 anyMatch 来检查是否有任何元素满足条件。

Main.java
void main() {

    List<Integer> numbers = List.of(2, 4, 6, 8, 10);
    
    boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0);
    System.out.println("Contains even numbers? " + hasEven);
    
    boolean hasOdd = numbers.stream().anyMatch(n -> n % 2 != 0);
    System.out.println("Contains odd numbers? " + hasOdd);
}

此示例检查列表是否包含任何偶数(在本例中为全部)以及任何奇数(在本例中为无)。 anyMatch 在找到第一个匹配项后停止处理。

$ java Main.java
Contains even numbers? true
Contains odd numbers? false

allMatch - 通用条件

我们可以使用 allMatch 来验证所有元素是否都满足条件。

Main.java
void main() {

    List<String> words = List.of("apple", "banana", "avocado", "apricot");
    
    boolean allStartWithA = words.stream().allMatch(s -> s.startsWith("a"));
    System.out.println("All words start with 'a'? " + allStartWithA);
    
    boolean allLongerThan3 = words.stream().allMatch(s -> s.length() > 3);
    System.out.println("All words longer than 3 chars? " + allLongerThan3);
}

此示例检查所有单词是否以 'a' 开头(false)以及所有单词是否都长于 3 个字符(true)。 allMatch 在找到第一个不匹配的元素后停止处理。

$ java Main.java
All words start with 'a'? false
All words longer than 3 chars? true

noneMatch - 缺席验证

我们可以使用 noneMatch 来确保没有元素满足条件。

Main.java
void main() {

    List<Integer> temperatures = List.of(22, 24, 19, 21, 25);
    
    boolean noneBelowZero = temperatures.stream().noneMatch(t -> t < 0);
    System.out.println("No temperatures below zero? " + noneBelowZero);
    
    boolean noneAbove30 = temperatures.stream().noneMatch(t -> t > 30);
    System.out.println("No temperatures above 30? " + noneAbove30);
}

此示例验证没有温度低于零(true),也没有温度高于 30(true)。 noneMatch 在找到第一个匹配的元素后停止处理。

$ java Main.java
No temperatures below zero? true
No temperatures above 30? true

空流行为

下一个示例展示了匹配操作在空流中的行为。

Main.java
void main() {

    List<String> emptyList = List.of();
    
    boolean any = emptyList.stream().anyMatch(s -> true);
    boolean all = emptyList.stream().allMatch(s -> false);
    boolean none = emptyList.stream().noneMatch(s -> true);
    
    System.out.println("anyMatch: " + any);
    System.out.println("allMatch: " + all);
    System.out.println("noneMatch: " + none);
}

此示例演示了空流的行为:anyMatch 返回 false,allMatch 返回 true(当然是 true),noneMatch 返回 true。

$ java Main.java
anyMatch: false
allMatch: true
noneMatch: true

复杂对象匹配

下一个示例演示了对自定义对象列表的匹配操作,使用 record 类来表示产品。

Main.java
record Product(String name, double price, boolean inStock) {}

void main() {

    List<Product> inventory = List.of(
        new Product("Laptop", 999.99, true),
        new Product("Phone", 699.99, false),
        new Product("Tablet", 349.99, true)
    );
    
    boolean anyExpensive = inventory.stream()
        .anyMatch(p -> p.price() > 800);
    System.out.println("Any expensive products? " + anyExpensive);
    
    boolean allInStock = inventory.stream()
        .allMatch(Product::inStock);
    System.out.println("All products in stock? " + allInStock);
    
    boolean noneFree = inventory.stream()
        .noneMatch(p -> p.price() == 0);
    System.out.println("No free products? " + noneFree);
}

此示例检查 Product 对象列表的各种条件,演示了匹配操作如何处理对象属性上的复杂谓词。

$ java Main.java
Any expensive products? true
All products in stock? false
No free products? true

短路行为

下一个示例演示了匹配操作的短路特性。

Main.java
void main() {

    boolean result = IntStream.range(1, 1000)
        .peek(n -> System.out.println("Processing: " + n))
        .anyMatch(n -> n % 42 == 0);
    
    System.out.println("Found multiple of 42? " + result);
}

此示例显示了 anyMatch 在找到第一个 42 的倍数后停止处理。 peek 操作显示实际处理了哪些数字。

$ java Main.java
Processing: 1
Processing: 2
...
Processing: 42
Found multiple of 42? true

与其他操作结合使用

下一个示例将匹配操作与其他流操作结合起来,以演示它们的灵活性。

Main.java
void main() {

    List<String> mixed = List.of("1", "2", "three", "4", "five");
    
    boolean allNumeric = mixed.stream()
        .map(s -> {
            System.out.println("Mapping: " + s);
            return s;
        })
        .filter(s -> s.length() == 1)
        .allMatch(s -> Character.isDigit(s.charAt(0)));
    
    System.out.println("All single chars are digits? " + allNumeric);
}

此示例检查是否所有单字符字符串都是数字,演示了匹配操作如何处理转换后的流。 请注意处理顺序。

$ java Main.java
Mapping: 1
Mapping: 2
Mapping: three
Mapping: 4
Mapping: five
All single chars are digits? true

来源

Java Stream 匹配文档

在本文中,我们探讨了 Java Stream 的匹配操作。 anyMatch、allMatch 和 noneMatch 提供了强大的方法来检查流元素上的条件,并具有高效的短路行为。 这些操作对于编写简洁高效的基于流的条件检查至关重要。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有Java教程