通用 "is null" 谓词

Generic "is null" predicate

我写了这个通用谓词:

private static <T> Predicate<T> isNull(){
    return Objects::isNull;
}

但我不能像这样将它与其他谓词结合使用:

private static Predicate<String> isEmpty(){
    return string -> string.isEmpty();
}

因为这个片段不会编译(期望 Predicate in or 操作):

isNull().or(isEmpty())

有解决办法吗?谢谢!

由于isNull()是泛型,编译器无法在这样组合时推断出泛型参数,因此您需要显式指定类型参数。

为此,您必须使用 class 名称进行限定,例如Test:

Test.<String>isNull().or(isEmpty())

完整示例:

public class Test {
    public static void main(String[] args) {
        Predicate<String> isNullOrEmpty = Test.<String>isNull().or(isEmpty());
        System.out.println(isNullOrEmpty.test(null));   // true
        System.out.println(isNullOrEmpty.test(""));     // true
        System.out.println(isNullOrEmpty.test("Foo"));  // false
    }
    private static <T> Predicate<T> isNull(){
        return Objects::isNull;
    }
    private static Predicate<String> isEmpty(){
        return string -> string.isEmpty();
    }
}

您也可以通过将每个部分分配给一个变量来解决它:

Predicate<String> isNull = isNull(); // String is inferred from assignment operator
Predicate<String> isEmpty = isEmpty();
Predicate<String> isNullOrEmpty = isNull.or(isEmpty);

或者只是第一部分:

Predicate<String> isNull = isNull();
Predicate<String> isNullOrEmpty = isNull.or(isEmpty());

当您调用 isNull() 时,没有上下文可以推断出 T 的实际类型。

isNull().or(..) 这里需要一个 Predicate<? super Object>,因此你不能将 Predicate<String> 传递给它。

翻转它们就可以了 (isEmpty().or(isNull())) isEmpty() 现在 returns 一个 Predicate<String>isEmpty.or(..) 期望一个 Predicate<? super String> 所以你可以传递一个 Predicate<Object>

但这不是你想要的,因为你想在检查是否为空之前进行空检查(感谢 Slaw@ 指出这一点。专注于使其编译我没有注意它的meaning/semantic)。

你可以通过写

给编译器提示类型T是什么
<YourClassName>.<String>isNull().or(isEmpty());

专门针对 String,您可能只是在寻找像这样的单个 Predicate -

private static Predicate<String> isNullOrEmpty() {
    return s -> s == null || s.isEmpty();
}

这可以进一步用作

List<String> strings = Arrays.asList("", "one", "two", null, "three");
strings.stream().filter(isNullOrEmpty()).forEach(System.out::println);
// ofcourse the above would print "null" and is less useful

或者在 Java11 中使用 Predicate.not 的能力,更直观和看似有用的方法是 -

List<String> strings = Arrays.asList("", "one", "two", null, "three");
strings.stream().filter(Predicate.not(isNullOrEmpty)).forEach(System.out::println); 
// this would print one, two and three

在我们的项目中,我们有一个小的解决方法:

private static <T> Predicate<T> allOr(Predicate<T> ... predicates) {
    return Arrays.stream(predicates).reduce(Predicate::or).orElse(x -> true);
}

并将其用于:

Predicate<String> both = allOr(isEmpty(), isNull());