在Java8中,使用方法引用非常简单,如String::isEmpty,但无法使用它否定的方法引用。本文内容即如何解决此问题使得我们能够更加全面地使用方法引用。
首先看一个使用方法引用的例子:
Stream.of("A", "", "B").filter(String::isEmpty).count()
上面代码的输出为1,即空字符串的数目。如果我们想要获取非空字符串的数目,就不能直接使用方法引用了。
Stream.of("A", "", "B").filter(s -> !s.isEmpty()).count()
Java8中的Predicate,有predicate.negate()可以转换为断言的否定形式,但String::isEmpty却无法这么做(String::isEmpty.negate()或者!String::isEmpty)。
因为方法引用并不是一个lambda或者函数接口,它能够被解析为一个或者多个函数接口。如,String::isEmpty至少可以被解析如下:
- Predicate<String>
- Function
为了解决上述的问题,我们可以通过某种机制显式地将方法引用转换为一个函数接口:
public static <T> Predicate<T> as(Predicate<T> predicate) { return predicate;}
通过使用一个静态方法,接受方法引用参数,返回一个函数接口,即可实现方法引用到函数接口的转换。接着,我们就可以使用方法引用来实现上面例子中的获取非空字符串的数目。
Stream.of("A", "", "B").filter(as(String::isEmpty).negate()).count();
进一步还能使用各种组合的Predicate。
.filter(as(String::isEmpty).negate().and("A"::equals))
由于一个方法引用可能会被解析为多种函数接口,因此如果我们实现很多参数不同的as方法,那么很容易造成混淆。 更好的方式则是在方法名中加入函数参数的类型来区分。