What decides which functional interface to create from a lambda?

流过昼夜 提交于 2020-12-05 07:27:20

问题


Please consider this example:

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);
    }
}

What interests me here is the first test. Why is it using MyConsumer instead of Consumer ? What if I had more different possible Consumers with the same lambda structure, who has priority ? Plus, the cast I do on Test 2 is marked as Redundant by my IDE. That means the lamdba is created as a MyConsumer first. Why so ?

I'm using IntelliJ Idea with Javac.


回答1:


It's according to the procedure of choosing the most specific method as defined by the language specification:

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

...

A functional interface type S is more specific than a functional interface type T for an expression e if T is not a subtype of S and one of the following is true (where U1 ... Uk and R1 are the parameter types and return type of the function type of the capture of S, and V1 ... Vk and R2 are the parameter types and return type of the function type of T):

  • If e is an explicitly typed lambda expression (§15.27.1), then one of the following is true:
  • R2 is void.

  • R1 <: R2.

  • R1 and R2 are functional interface types, and there is at least one result expression, and R1 is more specific than R2 for each result expression of e.

    (The result expression of a lambda expression with a block body is defined in §15.27.2; the result expression of a lambda expression with an expression body is simply the body itself.)

  • R1 is a primitive type, and R2 is a reference type, and there is at least one result expression, and each result expression of e is a standalone expression (§15.2) of a primitive type.

  • R1 is a reference type, and R2 is a primitive type, and there is at least one result expression, and each result expression of e is either a standalone expression of a reference type or a poly expression.

  • If e is an exact method reference expression (§15.13.1), then i) for all i (1 ≤ i ≤ k), Ui is the same as Vi, and ii) one of the following is true:
  • R2 is void.

  • R1 <: R2.

  • R1 is a primitive type, R2 is a reference type, and the compile-time declaration for the method reference has a return type which is a primitive type.

  • R1 is a reference type, R2 is a primitive type, and the compile-time declaration for the method reference has a return type which is a reference type.

  • If e is a parenthesized expression, then one of these conditions applies recursively to the contained expression.

  • If e is a conditional expression, then for each of the second and third operands, one of these conditions applies recursively.

Therefore, MyConsumer is more specific than Consumer because Consumer (T in the spec) is not a subtype and both have a return value of void.



来源:https://stackoverflow.com/questions/41981693/what-decides-which-functional-interface-to-create-from-a-lambda

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!