【问题标题】:Predicates in Java 8Java 8 中的谓词
【发布时间】:2026-01-24 17:45:01
【问题描述】:

我有一个程序可以分析某些属性的文本。代码的基本结构对于所有属性都是相同的,只是在一行中有所不同:webDataField.containsAttributeXYZ(); 如下所示:

for (int index = 0; index < fields.size(); index++) {
    WebDataField webDataField = fields.get(index);
    boolean expectedCondition = webDataField.containsAttributeXYZ(); // Varies at this line..

    Double score = evaluateBooleanCondition(actualCondition, expectedCondition);

    WebDataFields fieldName = webDataField.getFieldName();
    ...
}

我不想为每个条件编写相同的代码(并在代码中重复自己),我想编写一次代码的主体并将条件(评估为真或假)传递给方法。

我是 Java Predicate 的新手,但如果我理解正确,这正是 Java 中谓词的功能。

这是否会迫使我在自己的类中编写每个条件,然后让该类实现Predicate 接口?

如果是这样,函数(之前在包含类似函数的类中声明)将需要转换为:

class ContainsAttributeXYZ implements Predicate<Boolean>

这会导致代码迷失方向并引发程序中类数量的大量增加(因为每个函数都需要转换为一个类)

还是我误解了 Predicates 在 Java 中的工作方式?还有其他方法吗?

谢谢

【问题讨论】:

  • 我不确定你在问什么。 Predicate 不需要声明为类。例如,Predicate&lt;String&gt; p = (String s) -&gt; s.length() &gt; 5; 可以。
  • Predicate&lt;Boolean&gt; 没有多大意义。你可能想要Predicate&lt;WebDataField&gt;
  • 您添加了 [lambda] 标签,但显然不知道它们是什么?

标签: java oop lambda java-8 predicate


【解决方案1】:

这是一个将Predicate 作为参数的示例方法:

void processFields(List<WebDataField> fields, Predicate<WebDataField> predicate) {
    for (WebDataField webDataField : fields) {
        boolean expectedCondition = predicate.test(webDataField);
    }
}

您可以通过传递方法引用来调用它,如下所示:

processFields(fields, WebDataField::containsAttributeXYZ);
processFields(fields, WebDataField::containsAttributeABC);

其中containsAttributeXYZcontainsAttributeABC 是返回booleanWebDataField 类的方法。或者您可以在不修改 WebDataField 的情况下创建 lambda 内联。例如。 :

processFields(fields, w -> w.getFieldName().length() > 5);

你不需要创建实现Predicate的类

【讨论】:

    【解决方案2】:

    您无需创建新类即可创建Predicate。这是因为 Java 8 添加了 lambda 语法,您可以将其视为匿名内部类的简写,它实现了仅具有一个方法的接口。这是一个例子:

    Predicate<Boolean> containsXYZ = b -> {
        return !b;
    };
    

    这相当于:

    Predicate<Boolean> containsXYZ = new Predicate<Boolean>() {
        public boolean test(Boolean b) {
            return !b;
        }
    };
    

    如果您的谓词只返回单个表达式的结果,则可以将其缩短为:

    Predicate<Boolean> containsXYZ = b -> !b;
    

    或者,函数可以是对方法的引用:

    Predicate<Boolean> containsXYZ = MyClass::myMethod; // for static methods, or
    Predicate<Boolean> containsXYZ = this::myMethod; // for instance methods
    

    这是一个单行谓词,如果输入为假则返回真,反之亦然。现在,对于您的用例,您可能需要这样的东西:

    static void checkAttributes(Predicate<WebDataField> containsAttributeXYZ) {
        for (WebDataField webDataField : fields) {
            boolean expectedCondition = containsAttributeXYZ.test(webDataField);
            Double score = evaluateBooleanCondition(actualCondition, expectedCondition);
            WebDataFields fieldName = webDataField.getFieldName();
    
            ...
        }
    }
    

    如需详细了解 lambda 的工作原理,请阅读 Java Tutorial

    【讨论】:

    • b -&gt; !b 的写法相当冗长。大括号和 return 关键字不是必需的。
    • @VGR 同意,但我认为这对于具有 Java 背景的人(显然)以前从未见过 lambda(即 OP)可能更具可读性。这样,它看起来有点像一种方法。