【问题标题】:Composition of method reference方法参考的组成
【发布时间】:2014-12-19 04:57:32
【问题描述】:

这和这个问题有关:How to do function composition?

我注意到可以将方法引用分配给声明为Function 的变量,因此我假设它应该具有andThencompose 函数,因此我希望我们可以直接组合它们。但显然我们需要先将它们分配给声明为 Function 的变量(或在调用之前进行类型转换),然后才能对它们调用 andThencompose

我怀疑我可能对这应该如何工作有一些误解。

所以我的问题:

  1. 为什么在调用andThen 方法之前需要先进行类型转换或将其分配给变量?
  2. 究竟是什么类型的方法引用需要以这种方式完成?

下面的示例代码。

public class MyMethods{
    public static Integer triple(Integer a){return 3*a;}
    public static Integer quadruple(Integer a){return 4*a;}

    public int operate(int num, Function<Integer, Integer> f){
        return f.apply(num);
    }

    public static void main(String[] args){
        MyMethods methods = new MyMethods();
        int three = methods.operate(1, MyMethods::triple); // This is fine
        // Error below
        // int twelve = methods.operate(1, (MyMethods::triple).andThen(MyMethods::quadruple));
        // But this one is fine
        Function<Integer, Integer> triple = MyMethods::triple;
        Function<Integer, Integer> quadruple = MyMethods::quadruple;
        int twelve = methods.operate(1, triple.andThen(quadruple));
        // This one is also fine
        int twelve2 = methods.operate(1, ((Function<Integer, Integer>)MyMethods::triple).andThen(MyMethods::quadruple));
    }
}


更多错误说明

在 Eclipse 中,它以错误消息突出显示:

此表达式的目标类型必须是函数式接口

在 Java 8 编译器中,错误是:

java8test.java:14:错误:此处不需要方法引用 int 十二 = methods.operate(1, (MyMethods::triple).andThen(MyMethods::quadruple)); ^ 1 个错误

(实际上,为什么 Eclipse 中的错误与 Java 8 编译器中的错误不同?)

【问题讨论】:

    标签: java eclipse java-8 function-composition method-reference


    【解决方案1】:

    正如 Brian Goetz(Java lambda 项目负责人)所说,"Lambda expressions have no intrinsic type"(也适用于方法引用)。这就是为什么您需要在其方法可用之前强制转换(或分配)类型 Function

    Eclipse 显示与 JDK 编译器 (javac) 不同的错误消息的原因是 Eclipse 使用自己的 Java 编译器,称为 ecj,它是与 javac 完全不同的程序。顺便说一句,这就是为什么 Eclipse 可以在 JRE 上运行,而不需要完整的 JDK 安装。

    【讨论】:

    • 我明白了,这个问题是关于谓词的,这就是我在搜索中找不到它的原因。谢谢你的回答!
    【解决方案2】:

    如果您创建 static 辅助方法(其中所有函数都是参数而不是方法调用接收器),则无需类型转换或临时变量即可摆脱困境:

    static <T,V,R> Function<V, R> chain(
        Function<? super V, ? extends T> f1, Function<? super T, R> f2) {
    
        return f2.compose(f1);
    }
    

    那么你可以简单地说:

    int twelve = methods.operate(1, chain(MyMethods::triple, MyMethods::quadruple));
    

    但是,请记住,与简单的 lambda 表达式相比,以这种方式链接方法引用在源代码中既不会更短,也不会在运行时更高效:

    int twelve = methods.operate(1, i -> quadruple(triple(i)));
    

    请注意最后一个解决方案如何不需要类型转换、附加变量或辅助方法。如果您有一个适合需要函数的现有方法,但由多个方法引用组成一个函数并没有真正用处(在大多数情况下),则方法引用是一个很好的工具。

    【讨论】:

    • 嗯,是的,我忘了我们可以恢复使用 lambda 表达式。感谢您的意见!
    猜你喜欢
    • 2022-11-11
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    • 2018-08-20
    • 1970-01-01
    • 1970-01-01
    • 2019-07-29
    • 2020-10-12
    相关资源
    最近更新 更多