Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What decides which functional interface to create from a lambda?

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.

like image 881
Winter Avatar asked Feb 01 '17 14:02

Winter


People also ask

Which functional interface is used for lambda expression?

Runnable is a functional interface, that's why we can use lambda expression to create it's instance. Since run() method takes no argument, our lambda expression also have no argument.

How functional interfaces are implemented using lambda expression?

Lambda expression provides implementation of functional interface. An interface which has only one abstract method is called functional interface. Java provides an anotation @FunctionalInterface, which is used to declare an interface as functional interface.

Which functional interfaces does Java provide to serve as data types for lambda expressions?

function Description. Functional interfaces provide target types for lambda expressions and method references. Each functional interface has a single abstract method, called the functional method for that functional interface, to which the lambda expression's parameter and return types are matched or adapted.

What are the rules of defining a functional interface?

A functional interface must have exactly one abstract method. A functional interface has any number of default methods because they are not abstract and implementation already provided by the same. A functional interface declares an abstract method overriding one of the public methods from java. lang.


1 Answers

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.

like image 62
M A Avatar answered Sep 30 '22 14:09

M A