是什么决定从lambda创建哪个功能接口?

时间:2017-02-01 14:02:56

标签: java lambda java-8 functional-interface

请考虑这个例子:

import java.util.function.Consumer;

public class Example {
    public static void main(String[] args) {
        Example example = new Example();

        example.setConsumer(test -> System.out.println("passed string is " + test)); //uses MyConsumer, why ?
        example.getConsumer().accept("Test 1");

        example.setConsumer((MyConsumer<String>)test -> System.out.println("passed string is " + test)); //uses MyConsumer
        example.getConsumer().accept("Test 2");

        example.setConsumer((Consumer<String>)test -> System.out.println("passed string is " + test)); //uses Consumer
        example.getConsumer().accept("Test 3");
    }

    private Consumer<String> consumer;

    public Consumer<String> getConsumer() {
        return consumer;
    }

    public void setConsumer(Consumer<String> consumer) {
        this.consumer = consumer;
    }

    public void setConsumer(MyConsumer<String> consumer) {
        this.consumer = consumer;
    }

    @FunctionalInterface
    public interface MyConsumer<T> extends Consumer<T> {
        @Override
        default void accept(T value) {
            System.out.println("In consumer string: " + value); //example thing to do
            receive(value);
        }

        void receive(T value);
    }
}

我感兴趣的是第一次测试。为什么使用MyConsumer而不是Consumer?如果我有更多不同的可能的消费者具有相同的lambda结构,谁具有优先权呢?另外,我在测试2上执行的演员阵容被我的IDE标记为Redundant。这意味着lamdba首先被创建为MyConsumer。为什么这样?

我正在使用IntelliJ Idea和Javac。

1 个答案:

答案 0 :(得分:6)

根据语言规范定义的choosing the most specific method程序:

  

如果多个成员方法都可访问并适用于方法调用,则必须选择一个为运行时方法调度提供描述符。 Java编程语言使用选择最具体方法的规则。

     

...

     

如果T不是S的子类型且以下之一为真,则函数接口类型S对于表达式e的函数接口类型T 更具体(其中U1 ... Uk和R1是S的捕获函数类型的参数类型和返回类型,V1 ... Vk和R2是T)函数类型的参数类型和返回类型:

     
      
  • 如果e是显式类型的lambda表达式(第15.27.1节),则以下之一为真:
  •   
     
    
        
  • R2无效。

  •     
  • R1&lt;:R2。

  •     
  • R1和R2是功能接口类型,并且至少有一个结果表达式,并且对于e的每个结果表达式,R1比R2更具体。

             

    (具有块体的lambda表达式的结果表达式在第15.27.2节中定义;具有表达式主体的lambda表达式的结果表达式只是主体本身。)

  •     
  • R1是基本类型,R2是引用类型,并且至少有一个结果表达式,e的每个结果表达式都是基本类型的独立表达式(第15.2节)。

  •     
  • R1是引用类型,R2是基本类型,并且至少有一个结果表达式,e的每个结果表达式都是引用类型或多义表达式的独立表达式。

  •     
  
     
      
  • 如果e是精确的方法参考表达式(§15.13.1),则i)对于所有i(1≤i≤k),Ui与Vi相同,并且ii)以下之一为真: / LI>   
     
    
        
  • R2无效。

  •     
  • R1&lt;:R2。

  •     
  • R1是基本类型,R2是引用类型,方法引用的编译时声明具有返回类型,它是基本类型。

  •     
  • R1是引用类型,R2是基本类型,方法引用的编译时声明具有返回类型,它是引用类型。

  •     
  
     
      
  • 如果e是带括号的表达式,则其中一个条件以递归方式应用于包含的表达式。

  •   
  • 如果e是条件表达式,则对于第二个和第三个操作数中的每一个,递归地应用其中一个条件。

  •   

因此,MyConsumerConsumer更具体,因为Consumer(规范中的T)不是子类型,且返回值均为{{1} }。