方法参考的组成

时间:2014-12-19 04:57:32

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

这与此问题有关:How to do function composition?

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

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

所以我的问题:

  1. 在我们调用andThen方法之前,为什么我们需要首先进行类型转换或将其分配给变量?
  2. 以这种方式需要完成的方法引用的确切类型是什么?
  3. 以下示例代码。

    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中,它突出显示错误消息:

      

    此表达式的目标类型必须是功能接口

    Eclipse error about functional interface

    并且在Java 8编译器中错误是:

    java8test.java:14: error: method reference not expected here
            int twelve = methods.operate(1, (MyMethods::triple).andThen(MyMethods::quadruple));
                                             ^
    1 error
    

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

2 个答案:

答案 0 :(得分:14)

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

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

答案 1 :(得分:7)

如果创建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)));

注意最后一个解决方案不需要类型转换,附加变量和辅助方法。如果你已经存在一个适合需要函数的方法,那么方法引用是一个很好的工具,但是在多个方法引用中组合一个函数并不是很有用(在大多数情况下)。