在Java 8中,你可以使用方法引用来过滤流,例如:
Stream<String> s = ...;
long emptyStrings = s.filter(String::isEmpty).count();
是否有一种方法可以创建一个方法引用,它是现有方法引用的否定,例如:
long nonEmptyStrings = s.filter(not(String::isEmpty)).count();
我可以创建如下所示的not方法,但我想知道JDK是否提供了类似的东西。
static <T> Predicate<T> not(Predicate<T> p) { return o -> !p.test(o); }
谓词有方法和,或和否定。
然而,String::isEmpty不是一个谓词,它只是一个String ->布尔lambda,它仍然可以成为任何东西,例如Function<String,布尔>。首先需要进行类型推断。filter方法隐式地推断类型。但如果你在传递它作为参数之前对它求反,它就不再发生了。正如@axtavt提到的,显式推理可以被用作一种丑陋的方式:
s.filter(((Predicate<String>) String::isEmpty).negate()).count()
在其他答案中还有其他建议,静态而不是方法和lambda最有可能是最好的想法。tl和dr部分到此结束。
但是,如果您想更深入地理解lambda类型推断,我想通过示例更深入地解释它。看看这些,看看会发生什么:
Object obj1 = String::isEmpty;
Predicate<String> p1 = s -> s.isEmpty();
Function<String, Boolean> f1 = String::isEmpty;
Object obj2 = p1;
Function<String, Boolean> f2 = (Function<String, Boolean>) obj2;
Function<String, Boolean> f3 = p1::test;
Predicate<Integer> p2 = s -> s.isEmpty();
Predicate<Integer> p3 = String::isEmpty;
obj1 doesn't compile - lambdas need to infer a functional interface (= with one abstract method)
p1 and f1 work just fine, each inferring a different type
obj2 casts a Predicate to Object - silly but valid
f2 fails at runtime - you cannot cast Predicate to Function, it's no longer about inference
f3 works - you call the predicate's method test that is defined by its lambda
p2 doesn't compile - Integer doesn't have isEmpty method
p3 doesn't compile either - there is no String::isEmpty static method with Integer argument
另一种选择是在明确的上下文中使用lambda强制转换为一个类:
public static class Lambdas {
public static <T> Predicate<T> as(Predicate<T> predicate){
return predicate;
}
public static <T> Consumer<T> as(Consumer<T> consumer){
return consumer;
}
public static <T> Supplier<T> as(Supplier<T> supplier){
return supplier;
}
public static <T, R> Function<T, R> as(Function<T, R> function){
return function;
}
}
... 然后静态导入实用程序类:
stream.filter(as(String::isEmpty).negate())