【问题标题】:method reference in java 8?java 8中的方法参考?
【发布时间】:2019-03-14 17:58:53
【问题描述】:

我在教程中读到,在使用方法引用时,参数必须在功能接口的方法和我们所引用的方法中匹配。 所以我得到以下错误。

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

    }
}

现在我已经明白为什么我会收到这个错误 看下面的代码sn -p

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()没有任何参数,在这种情况下,即使参数不匹配,它也不会抛出任何错误。

请帮助我理解这一点?

【问题讨论】:

    标签: java methods lambda reference functional-interface


    【解决方案1】:

    方法参考

    Transaction::getId
    

    等于 lambda 表达式

    (Transaction t) -> t.getId()
    

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

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

    【讨论】:

      【解决方案2】:

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

      否则,给定具有参数类型 P1、...、Pn 和一组可能适用的方法的目标函数类型,编译时声明为选择如下:

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

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

        在第二次搜索中,如果P1, ..., Pn 不为空且P1 是ReferenceType,则方法引用表达式被视为方法调用表达式,其参数表达式类型为 P2, ..., Pn.

        如果第一次搜索产生了一个最具体的方法static,并且第二次搜索产生的适用方法集不包含非static方法,那么编译时声明是最指定的方法第一次搜索。

        否则,如果第一次搜索产生的适用方法集不包含static方法,而第二次搜索产生的最具体的方法不是static,则编译时声明是最具体的第二次搜索的方法。

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

      在您的顶级示例中,m1 方法是 static,并且没有可以隐式作为第一个参数的实例,因此“第二次搜索”在这里不适用。

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

      【讨论】:

        【解决方案3】:

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

        apply 函数将参数作为一种类型的数据接收并返回另一种类型的数据。在你的情况下,它好像:

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

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

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

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

        Consumer<Integer> consumer = MethodRefTest::m1
        

        【讨论】:

        • 要真正创建Runnable,请将其输入为Runnable r = () -&gt; m1(2); // replacing 2 with any integer value
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多