Java 8中的方法参考?

时间:2019-03-14 17:58:54

标签: java methods lambda reference functional-interface

我在教程中已经读到,在使用方法引用时,必须在函数接口的方法和我们要引用的方法中匹配参数。 因此,我遇到了以下错误。

public class MethodRefTest 
{
    public static void m1(int i)
    {
        System.out.println("Hey in method 1");
    }


    public static void main(String[] args)
    {

        Runnable r=MethodRefTest::m1; //Compile time error

    }
}

现在我已经了解了为什么我会收到该错误 看下面的代码片段

package com;

public class Transaction {

    private int id;
    private int value;

    public Transaction(int id,int value)
    {
        this.id=id;
        this.value=value;
    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }


}


package com;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class MethodRefTest {

    public static void main(String[] args)
    {

        Transaction t1=new Transaction(1,20);
        Transaction t2=new Transaction(2,30);
        List<Transaction> list=new ArrayList<Transaction>();
        list.add(t1);
        list.add(t2);
        List<Integer> intList=list.stream().map(Transaction::getId).collect(Collectors.toList());
        System.out.println(intList);

    }
}

在我使用的map方法中,它接受Function FunctionalInterface ...但是我使用的方法引用没有任何参数,但是Function的apply(T t)方法只有一个参数,而getId()没有任何参数,在这种情况下,即使参数不匹配也不会引发任何错误。

请帮助我理解这一点?

3 个答案:

答案 0 :(得分:0)

  

,但是Function的apply(T t)方法有一个参数,而getId()   没有任何论据

apply函数将参数作为一种数据类型并返回另一种数据。就您而言,就好像:

public Integer apply(Transaction transaction) {
    return transaction.getId();
}

Function操作中完整的map当然将转换的输入和输出类型定义为:

new Function<Transaction, Integer>() {
    @Override
    public Integer apply(Transaction transaction) {
        return transaction.getId();
    }
}

相反,在您的代码m1中需要为其提供整数类型的参数,这将导致void输出。因此,您的实现匹配为Consumer,并可以表示为:

Consumer<Integer> consumer = MethodRefTest::m1

答案 1 :(得分:0)

方法参考

Transaction::getId

等于 lambda表达式

(Transaction t) -> t.getId()

您会看到接受Transaction参数并返回int

这是一个完全有效的Function<Transaction, Integer>签名,因为它确实满足了要求。

答案 2 :(得分:0)

允许Java编译器将方法引用与带有 n-1 参数的非static方法匹配,就好像它匹配一样,对象本身就是第一个参数。相关的section of the JLS is 15.13.1

  

否则,给定具有参数类型P 1 ,...,P n 的目标函数类型以及一组可能适用的方法,则编译时声明为选择如下:

     
      
  • 如果方法引用表达式的格式为 ReferenceType :: [TypeArguments]标识符,则将对最适用的方法执行两次搜索。每次搜索均按照§15.12.2.2至§15.12.2.5的规定进行,以下说明。每次搜索都会产生一组适用的方法,并且可能会指定一组最具体的方法。如果出现第15.12.2.4节中指定的错误,则适用的方法集为空。如果出现第15.12.2.5节中指定的错误,则没有最具体的方法。

         

    在第一次搜索中,方法引用被视为使用类型为P 1 ,...,P n 的参数表达式进行的调用。类型参数(如果有)由方法引用表达式给出。

         

    在第二次搜索中,如果P 1 ,...,P n 不为空,并且P 1 是< em> ReferenceType ,则将方法引用表达式视为带有参数类型为P 2 ,...,P n 。

         

    如果第一个搜索产生的最具体方法为static,而第二个搜索产生的适用方法集不包含任何非static方法,则编译时声明为最明确的首次搜索方法。

         

    否则,如果第一次搜索产生的一组适用方法不包含任何static方法,而第二次搜索产生的是最非static的最特定方法,则进行编译时声明是第二次搜索的最具体方法。

  •   

“首次搜索”是方法参数与功能接口类型的直接匹配。 “第二次搜索”增加了一些灵活性,因为来自方法引用的对象实例本身可以用作与功能接口的第一个参数匹配。

在您的顶级示例中,m1方法为static,并且没有任何实例可以隐式地成为第一个参数,因此“第二个搜索”不适用于此处。

在您的底部示例中,getId不是静态的,并且上面的“第二搜索”适用。这里,getId没有参数,因此参数“ P2-Pn”的集合为空。但是,对象本身是隐式的第一个参数,因此它与Function<Transaction, Integer>中的map方法所期望的功能签名Stream相匹配。