使您的Java 8方法引用生效

方法参考

众所周知,我们可以使用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<String>
  • Function<String, Boolean>

因此,我们需要以某种方式解决所有潜在的歧义,并确定我们要将方法参考转换为哪个功能接口。 阅读这篇文章,了解如何部分解决此问题。 我使用了开源项目Speedment中提供的代码,该代码使数据库看起来像Java 8 Streams。 随意尝试Speedment out。

Speedment还包含谓词生成器,使您可以直接使用诸如Entity.NAME::isEmpty和Entity.NAME::isNotEmpty之类的函数。

解析方法参考

通过以静态方法的形式引入一些“管道”,可以部分解决该问题,该方法采用“方法参考”并将其作为特定功能接口的视图返回。 考虑以下简短的静态方法:

public static <T> Predicate<T> as(Predicate<T> 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。

import java.util.function.*;

/**
 *
 * @author Per Minborg
 */
public class FunctionCastUtil {

    public static <T, U> BiConsumer<T, U> asBiConsumer(BiConsumer<T, U> biConsumer) {
        return biConsumer;
    }

    public static <T, U, R> BiFunction<T, U, R> asBiFunction(BiFunction<T, U, R> biFunction) {
        return biFunction;
    }

    public static <T> BinaryOperator<T> asBinaryOperator(BinaryOperator<T> binaryOperator) {
        return binaryOperator;
    }

    public static <T, U> BiPredicate<T, U> asBiPredicate(BiPredicate<T, U> biPredicate) {
        return biPredicate;
    }

    public static BooleanSupplier asBooleanSupplier(BooleanSupplier booleanSupplier) {
        return booleanSupplier;
    }

    public static <T> Consumer<T> asConsumer(Consumer<T> consumer) {
        return consumer;
    }

    public static DoubleBinaryOperator asDoubleBinaryOperator(DoubleBinaryOperator doubleBinaryOperator) {
        return doubleBinaryOperator;
    }

    public static DoubleConsumer asDoubleConsumer(DoubleConsumer doubleConsumer) {
        return doubleConsumer;
    }

    public static <R> DoubleFunction<R> asDoubleFunction(DoubleFunction<R> 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 <T, R> Function<T, R> asFunction(Function<T, R> function) {
        return function;
    }

    public static IntBinaryOperator asIntBinaryOperator(IntBinaryOperator intBinaryOperator) {
        return intBinaryOperator;
    }

    public static IntConsumer asIntConsumer(IntConsumer intConsumer) {
        return intConsumer;
    }

    public static <R> IntFunction<R> asIntFunction(IntFunction<R> 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 <R> LongFunction<R> asLongFunction(LongFunction<R> longFunction) {
        return longFunction;
    }

    public static LongPredicate asLongPredicate(LongPredicate longPredicate) {
        return longPredicate;
    }

    public static <T> 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 <T> ObjDoubleConsumer<T> asObjDoubleConsumer(ObjDoubleConsumer<T> objDoubleConsumer) {
        return objDoubleConsumer;
    }

    public static <T> ObjIntConsumer<T> asObjIntConsumer(ObjIntConsumer<T> objIntConsumer) {
        return objIntConsumer;
    }

    public static <T> ObjLongConsumer<T> asObjLongConsumer(ObjLongConsumer<T> objLongConsumer) {
        return objLongConsumer;
    }

    public static <T> Predicate<T> asPredicate(Predicate<T> predicate) {
        return predicate;
    }

    public static <T> Supplier<T> asSupplier(Supplier<T> supplier) {
        return supplier;
    }

    public static <T, U> ToDoubleBiFunction<T, U> asToDoubleBiFunction(ToDoubleBiFunction<T, U> toDoubleBiFunction) {
        return toDoubleBiFunction;
    }

    public static <T> ToDoubleFunction<T> asToDoubleFunction(ToDoubleFunction<T> toDoubleFunction) {
        return toDoubleFunction;
    }

    public static <T, U> ToIntBiFunction<T, U> asToIntBiFunction(ToIntBiFunction<T, U> toIntBiFunction) {
        return toIntBiFunction;
    }

    public static <T> ToIntFunction<T> asToIntFunction(ToIntFunction<T> ioIntFunction) {
        return ioIntFunction;
    }

    public static <T, U> ToLongBiFunction<T, U> asToLongBiFunction(ToLongBiFunction<T, U> toLongBiFunction) {
        return toLongBiFunction;
    }

    public static <T> ToLongFunction<T> asToLongFunction(ToLongFunction<T> toLongFunction) {
        return toLongFunction;
    }

    public static <T> UnaryOperator<T> asUnaryOperator(UnaryOperator<T> unaryOperator) {
        return unaryOperator;
    }

    private FunctionCastUtil() {
    }

}

因此,在静态导入相关方法之后,我们可以编写:

Stream.of("A", "", "B").filter(asPredicate(String::isEmpty).negate()).count();

更好的解决方案

如果所有功能接口本身都包含一个静态方法,该方法可以采用适当的“方法引用”并将其转换为类型化的功能接口,那将更好。 例如,标准的Java Predicate功能接口将如下所示:

@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);

    default Predicate<T> and(Predicate<? super T> other) {...}

    default Predicate<T> negate() {...}

    default Predicate<T> or(Predicate<? super T> other) {...}

    static <T> Predicate<T> isEqual(Object targetRef) {...}

    // New proposed support method to return a 
    // Predicate view of a Functional Reference 
    public static <T> Predicate<T> of(Predicate<T> 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值