ZetCode

Java Pattern.asPredicate 方法

上次修改时间:2025 年 4 月 20 日

Pattern.asPredicate 方法在 Java 8 中引入,作为 java.util.regex.Pattern 类的一部分。 它将编译的正则表达式模式转换为 Predicate<String>,用于函数式风格的操作。 此方法在处理 Java Stream 时特别有用。

返回的谓词测试输入字符串是否包含与模式匹配的内容。 这等效于对模式调用 matcher(input).find。 该谓词可以在任何需要 Predicate<String> 的地方使用。

基本定义

Java 中的 Predicate 是一个函数式接口,表示一个参数的布尔值函数。 它通常用于过滤操作。 Pattern 类表示编译的正则表达式。

asPredicate 通过创建一个测试字符串与模式的谓词来桥接这些概念。 该方法要求首先编译该模式。 结果谓词是线程安全的并且可以重复使用。

Basic asPredicate 示例

此示例演示了 asPredicate 的最简单用法。 我们创建一个用于电子邮件验证的模式,并将其用作谓词来测试字符串。

BasicPredicateExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.function.Predicate;

public class BasicPredicateExample {

    public static void main(String[] args) {
        Pattern emailPattern = Pattern.compile("^[\\w.-]+@[\\w.-]+\\.[a-z]{2,}$");
        Predicate<String> emailPredicate = emailPattern.asPredicate();
        
        System.out.println("test@example.com: " + emailPredicate.test("test@example.com"));
        System.out.println("invalid.email: " + emailPredicate.test("invalid.email"));
    }
}

在此示例中,我们编译一个电子邮件正则表达式模式并将其转换为谓词。 谓词的 test 方法检查输入字符串是否包含与模式匹配的内容。 第一个测试返回 true,而第二个测试返回 false。

使用 asPredicate 过滤 Stream

asPredicate 最强大的用途之一是过滤流。 此示例演示了如何过滤字符串列表以仅包含有效的电话号码。

StreamFilterExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.List;
import java.util.stream.Collectors;

public class StreamFilterExample {
    public static void main(String[] args) {
        Pattern phonePattern = Pattern.compile("^\\+?[0-9]{10,15}$");
        List<String> contacts = List.of(
            "+1234567890", "invalid", "9876543210", "123-456-7890"
        );
        
        List<String> validPhones = contacts.stream()
            .filter(phonePattern.asPredicate())
            .collect(Collectors.toList());
            
        System.out.println("Valid phone numbers: " + validPhones);
    }
}

在这里,我们从字符串列表创建一个流,并使用我们的模式谓词对其进行过滤。 只有与电话号码模式匹配的字符串才能通过过滤器。 结果仅包含原始列表中的有效电话号码。

组合谓词

可以使用 Predicate 接口的默认方法将 asPredicate 与其他谓词组合。 此示例演示了如何创建复杂的验证逻辑。

CombinedPredicatesExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.function.Predicate;

public class CombinedPredicatesExample {

    public static void main(String[] args) {
        Pattern uppercasePattern = Pattern.compile("[A-Z]");
        Pattern digitPattern = Pattern.compile("[0-9]");
        
        Predicate<String> hasUppercase = uppercasePattern.asPredicate();
        Predicate<String> hasDigit = digitPattern.asPredicate();
        
        Predicate<String> isStrongPassword = hasUppercase.and(hasDigit)
            .and(s -> s.length() >=  8);
            
        System.out.println("Password1: " + isStrongPassword.test("Password1"));
        System.out.println("weakpass: " + isStrongPassword.test("weakpass"));
    }
}

我们创建两个模式谓词来检查大写字母和数字。 然后,我们使用 and 将它们与长度检查结合起来。 结果谓词仅对满足所有三个条件的字符串返回 true。

不区分大小写的谓词

此示例演示了如何使用模式标志创建不区分大小写的谓词。 无论字母大小写如何,该谓词都将匹配。

CaseInsensitivePredicate.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.stream.Stream;

public class CaseInsensitivePredicate {

    public static void main(String[] args) {
        Pattern namePattern = Pattern.compile("john", Pattern.CASE_INSENSITIVE);
        
        Stream.of("John", "JOHN", "john", "Jane")
            .filter(namePattern.asPredicate())
            .forEach(System.out::println);
    }
}

CASE_INSENSITIVE 标志使模式匹配不区分大小写。 该谓词将匹配 "john" 的所有大小写变体,但不匹配其他名称。 打印 "john" 的所有三个大小写变体。

asPredicate 与 asMatchPredicate

Java 11 引入了 asMatchPredicate,它在匹配行为方面与 asPredicate 不同。 此示例比较了两者。

PredicateComparison.java
package com.zetcode;

import java.util.regex.Pattern;

public class PredicateComparison {

    public static void main(String[] args) {
        Pattern wordPattern = Pattern.compile("hello");
        
        String input1 = "hello";
        String input2 = "hello there";
        
        System.out.println("asPredicate:");
        System.out.println(input1 + ": " + wordPattern.asPredicate().test(input1));
        System.out.println(input2 + ": " + wordPattern.asPredicate().test(input2));
        
        System.out.println("\nasMatchPredicate:");
        System.out.println(input1 + ": " + wordPattern.asMatchPredicate().test(input1));
        System.out.println(input2 + ": " + wordPattern.asMatchPredicate().test(input2));
    }
}

asPredicate 的行为类似于 find,匹配字符串中的任何位置。 asMatchPredicate 的行为类似于 matches,要求整个字符串匹配。 两个输入都与 asPredicate 匹配,但只有完全匹配才适用于 asMatchPredicate

在集合中使用谓词

此示例演示了如何将模式谓词与诸如 removeIf 之类的集合操作一起使用。 我们将从列表中删除所有无效的 ID。

CollectionRemoveExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.List;

public class CollectionRemoveExample {

    public static void main(String[] args) {

        Pattern idPattern = Pattern.compile("^[A-Z]{2}[0-9]{4}$");
        List<String> ids = new ArrayList<>(List.of(
            "AB1234", "INVALID", "CD5678", "XY90", "EF9012"
        ));
        
        ids.removeIf(idPattern.asPredicate().negate());
        System.out.println("Valid IDs: " + ids);
    }
}

我们为有效 ID(2 个字母后跟 4 个数字)创建一个谓词,并使用带有否定谓词的 removeIf 来删除无效条目。 negate 方法反转谓词的逻辑。 列表中仅保留有效的 ID。

使用谓词进行复杂验证

对于更复杂的验证,我们可以链接多个模式谓词。 此示例验证具有特定格式要求的产品代码。

ComplexValidationExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.function.Predicate;

public class ComplexValidationExample {

    public static void main(String[] args) {
        Pattern startsWithLetter = Pattern.compile("^[A-Z]");
        Pattern containsDigit = Pattern.compile("[0-9]");
        Pattern endsWithLetter = Pattern.compile("[A-Z]$");
        
        Predicate<String> isValidProductCode = startsWithLetter.asPredicate()
            .and(containsDigit.asPredicate())
            .and(endsWithLetter.asPredicate())
            .and(s -> s.length() >=  5 &&  s.length() <=  10);
            
        System.out.println("A123B: " + isValidProductCode.test("A123B"));
        System.out.println("1ABC: " + isValidProductCode.test("1ABC"));
        System.out.println("AB1234567C: " + isValidProductCode.test("AB1234567C"));
    }
}

我们将三个模式谓词与长度检查结合起来以验证产品代码。 代码必须以字母开头和结尾,至少包含一个数字,并且长度为 5-10 个字符。 只有满足所有条件的字符串才能通过验证。

来源

Java Pattern.asPredicate 文档

Pattern.asPredicate 方法提供了一种强大的方法,可以将正则表达式模式匹配与 Java 的函数式编程功能集成。 它对于现代 Java 代码中的过滤和验证任务特别有用。

作者

我的名字是 Jan Bodnar,我是一位敬业的程序员,在该领域拥有多年的经验。 我于 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和八本电子书。 凭借超过八年的教学经验,我致力于分享我的知识并帮助其他人掌握编程概念。

列出所有Java教程