Java 8中的谓词

6

我有一个程序,用于分析文本的某些属性。代码的基本结构对于所有属性都是相同的,只有一行不同: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>

这会导致代码变得混乱,并触发程序中类的数量大幅增加(因为每个函数都需要转换为一个类)。
或者我对Java中的谓词工作方式有什么误解吗?还有其他方法可以实现这个功能吗?
谢谢。

我不确定你在问什么。Predicate 不需要声明为一个类。例如,Predicate<String> p = (String s) -> s.length() > 5; 就可以了。 - bradimus
5
“Predicate<Boolean>” 不太合理。您可能想要使用 “Predicate<WebDataField>”。 - Thomas Fritsch
你是怎么加上 [lambda] 标签的,但显然不知道它们是什么的? - 4castle
2个回答

5

这里是一个以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);

其中containsAttributeXYZcontainsAttributeABCWebDataField类的方法,返回boolean类型。或者你可以创建一个内联lambda而不修改WebDataField。例如:

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教程


1
这是一种相当冗长的写法,写成 b -> !b 就可以了,花括号和 return 关键字都不必要。 - VGR
2
@VGR同意,但我认为对于一个Java背景的人来说更易读,他们(显然)从未见过lambda表达式(即OP)。这样,它看起来有点像一个方法。 - Brian McCutchon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接