方法参考
众所周知,我们可以使用Java 8中的方法引用 (例如String::isEmpty
来引用例如在元素上流式传输时使用的方法。 看一下以下代码片段:
Stream.of("A", "", "B").filter(Stream::isEmpty).count();
它将产生结果1(因为流中只有一个空元素)。 但是,如果要过滤掉非空字符串,则需要编写.filter(s -> !s.isEmpty())
,这是一个Lambda。 显然,这里有一个令人讨厌的不对称。 我们可以使用方法参考,但不能使用它的否定。 我们可以编写predicate.negate()
但不能编写Stream::isEmpty.negate()
或!Stream::isEmpty
。
这是为什么? 这是因为方法引用不是Lambda或功能接口。 但是,可以使用Java的类型推断将方法引用解析为一个或多个功能接口。 实际上,我们的示例String::isEmpty
至少可以解析为:
-
Predicate
-
Function
因此,我们需要以某种方式解决所有潜在的歧义,并确定我们要将方法参考转换为哪个功能接口。 阅读这篇文章,了解如何部分解决此问题。 我使用了开源项目Speedment中提供的代码,该代码使数据库看起来像Java 8 Streams。 随意尝试Speedment out。
Speedment还包含谓词生成器,使您可以直接使用诸如Entity.NAME::isEmpty和Entity.NAME::isNotEmpty之类的函数。
解析方法参考
通过以静态方法的形式引入一些“管道”,可以部分解决该问题,该方法采用“方法参考”并将其作为特定功能接口的视图返回。 考虑以下简短的静态方法:
public static Predicate as(Predicate predicate) {
return predicate;
}
现在,如果我们静态导入该方法,实际上,我们可以更轻松地使用“方法引用”,如以下简短示例所示:
Stream.of("A", "", "B").filter(as(String::isEmpty).negate()).count();
该代码将返回2,这是流中非空元素的数量。 在方法参考用法方面,这是向前迈出的一步。 另一个好处是,此解决方案使我们可以更轻松地组成谓词,如下所示:
.filter(as(String::isEmpty).negate().and("A"::equals))
解决所有方法参考
但是,我们仍然需要解决一个问题。 我们不能简单地开始创建很多静态的as()
函数,因为方法引用可能可以用本文开头列出的相同方式解析为几种潜在的as()
方法。 因此,更好的方法是将功能接口类型名称附加到每个静态方法,从而使我们能够以编程方式选择特定的方法参考到功能接口转换方法。 这是一个实用程序类,它允许将方法引用转换为驻留在标准Java包java.util.function
中的任何匹配的Functional Interface。
- 在此处直接从GitHub下拉最新版本
import java.util.function.*;
/**
*
* @author Per Minborg
*/
public class FunctionCastUtil {
public static BiConsumer asBiConsumer(BiConsumer biConsumer) {
return biConsumer;
}
public static BiFunction asBiFunction(BiFunction biFunction) {
return biFunction;
}
public static BinaryOperator asBinaryOperator(BinaryOperator binaryOperator) {
return binaryOperator;
}
public static BiPredicate asBiPredicate(BiPredicate biPredicate) {
return biPredicate;
}
public static BooleanSupplier asBooleanSupplier(BooleanSupplier booleanSupplier) {
return booleanSupplier;
}
public static Consumer asConsumer(Consumer consumer) {
return consumer;
}
public static DoubleBinaryOperator asDoubleBinaryOperator(DoubleBinaryOperator doubleBinaryOperator) {
return doubleBinaryOperator;
}
public static DoubleConsumer asDoubleConsumer(DoubleConsumer doubleConsumer) {
return doubleConsumer;
}
public static DoubleFunction asDoubleFunction(DoubleFunction doubleFunction) {
return doubleFunction;
}
public static DoublePredicate asDoublePredicate(DoublePredicate doublePredicate) {
return doublePredicate;
}
public static DoubleToIntFunction asDoubleToIntFunction(DoubleToIntFunction doubleToIntFunctiontem) {
return doubleToIntFunctiontem;
}
public static DoubleToLongFunction asDoubleToLongFunction(DoubleToLongFunction doubleToLongFunction) {
return doubleToLongFunction;
}
public static DoubleUnaryOperator asDoubleUnaryOperator(DoubleUnaryOperator doubleUnaryOperator) {
return doubleUnaryOperator;
}
public static Function asFunction(Function function) {
return function;
}
public static IntBinaryOperator asIntBinaryOperator(IntBinaryOperator intBinaryOperator) {
return intBinaryOperator;
}
public static IntConsumer asIntConsumer(IntConsumer intConsumer) {
return intConsumer;
}
public static IntFunction asIntFunction(IntFunction intFunction) {
return intFunction;
}
public static IntPredicate asIntPredicate(IntPredicate intPredicate) {
return intPredicate;
}
public static IntSupplier asIntSupplier(IntSupplier intSupplier) {
return intSupplier;
}
public static IntToDoubleFunction asIntToDoubleFunction(IntToDoubleFunction intToDoubleFunction) {
return intToDoubleFunction;
}
public static IntToLongFunction asIntToLongFunction(IntToLongFunction intToLongFunction) {
return intToLongFunction;
}
public static IntUnaryOperator asIntUnaryOperator(IntUnaryOperator intUnaryOperator) {
return intUnaryOperator;
}
public static LongBinaryOperator asLongBinaryOperator(LongBinaryOperator longBinaryOperator) {
return longBinaryOperator;
}
public static LongConsumer asLongConsumer(LongConsumer longConsumer) {
return longConsumer;
}
public static LongFunction asLongFunction(LongFunction longFunction) {
return longFunction;
}
public static LongPredicate asLongPredicate(LongPredicate longPredicate) {
return longPredicate;
}
public static LongSupplier asLongSupplier(LongSupplier longSupplier) {
return longSupplier;
}
public static LongToDoubleFunction asLongToDoubleFunction(LongToDoubleFunction longToDoubleFunction) {
return longToDoubleFunction;
}
public static LongToIntFunction asLongToIntFunction(LongToIntFunction longToIntFunction) {
return longToIntFunction;
}
public static LongUnaryOperator asLongUnaryOperator(LongUnaryOperator longUnaryOperator) {
return longUnaryOperator;
}
public static ObjDoubleConsumer asObjDoubleConsumer(ObjDoubleConsumer objDoubleConsumer) {
return objDoubleConsumer;
}
public static ObjIntConsumer asObjIntConsumer(ObjIntConsumer objIntConsumer) {
return objIntConsumer;
}
public static ObjLongConsumer asObjLongConsumer(ObjLongConsumer objLongConsumer) {
return objLongConsumer;
}
public static Predicate asPredicate(Predicate predicate) {
return predicate;
}
public static Supplier asSupplier(Supplier supplier) {
return supplier;
}
public static ToDoubleBiFunction asToDoubleBiFunction(ToDoubleBiFunction toDoubleBiFunction) {
return toDoubleBiFunction;
}
public static ToDoubleFunction asToDoubleFunction(ToDoubleFunction toDoubleFunction) {
return toDoubleFunction;
}
public static ToIntBiFunction asToIntBiFunction(ToIntBiFunction toIntBiFunction) {
return toIntBiFunction;
}
public static ToIntFunction asToIntFunction(ToIntFunction ioIntFunction) {
return ioIntFunction;
}
public static ToLongBiFunction asToLongBiFunction(ToLongBiFunction toLongBiFunction) {
return toLongBiFunction;
}
public static ToLongFunction asToLongFunction(ToLongFunction toLongFunction) {
return toLongFunction;
}
public static UnaryOperator asUnaryOperator(UnaryOperator unaryOperator) {
return unaryOperator;
}
private FunctionCastUtil() {
}
}
因此,在静态导入相关方法之后,我们可以编写:
Stream.of("A", "", "B").filter(asPredicate(String::isEmpty).negate()).count();
更好的解决方案
如果所有功能接口本身都包含一个静态方法,该方法可以采用适当的“方法引用”并将其转换为类型化的功能接口,那将更好。 例如,标准的Java Predicate
功能接口将如下所示:
@FunctionalInterface
public interface Predicate {
boolean test(T t);
default Predicate and(Predicate super T> other) {...}
default Predicate negate() {...}
default Predicate or(Predicate super T> other) {...}
static Predicate isEqual(Object targetRef) {...}
// New proposed support method to return a
// Predicate view of a Functional Reference
public static Predicate of(Predicate predicate) {
return predicate;
}
}
这将使我们能够编写:
Stream.of("A", "", "B").filter(Predicate.of(String::isEmpty).negate()).count();
我个人认为看起来不错!
与您最近的Open JDK开发人员联系并提出建议!
翻译自: https://www.javacodegeeks.com/2016/03/put-java-8-method-references-work.html