Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I need a functional Interface to work with lambdas?

I think this question is already somewhere out there, but I wasn't able to find it.

I don't understand, why it's necessary to have a functional interface to work with lambdas. Consider the following example:

public class Test {

    public static void main(String...args) {
        TestInterface i = () -> System.out.println("Hans");
//      i = (String a) -> System.out.println(a);

        i.hans();
//      i.hans("Hello");
    }
}

public interface TestInterface {
    public void hans();
//  public void hans(String a);
}

This works without problems, but if you uncomment the commented lines, it doesn't. Why? In my understanding, the compiler should be able to distinguish the two methods, since they have different input-parameters. Why do I need a functional interface and blow up my code?

EDIT: The linked duplicates didn't answer my question because I'm asking about different method-parameters. But I got some really useful answers here, thanks to everyone who helped! :)

EDIT2: Sorry, I'm obviously not a native speaker, but to precise myself:

public interface TestInterface {
    public void hans();                 //has no input parameters</br>
    public void hans(String a);         //has 1 input parameter, type String</br>
    public void hans(String a, int b);  //has 2 input parameters, 1. type = String, 2. type = int</br>
    public void hans(int a, int b);     //has also 2 input parameters, but not the same and a different order than `hans(String a, int a);`, so you could distinguish both
}

public class Test {

    public static void main(String...args) {
        TestInterface i = () -> System.out.println("Hans");
        i = (String a) -> System.out.println(a);
        i = (String a, int b) -> System.out.println(a + b);
        i = (int a, int b) -> System.out.println(a);

        i.hans(2, 3);   //Which method would be called? Of course the one that would take 2 integer arguments. :)
    }
}

All I'm asking is about the arguments. The method name doesn't matter, but each method takes an unique order of different arguments and because of that, Oracle could have implemented this feature instead just making a single method possible per "Lambda-Interface".

like image 960
codepleb Avatar asked Oct 08 '15 08:10

codepleb


People also ask

Why do we need functional interface for lambda?

Lambda Expression Objects are the base of java programming language and we can never have a function without an Object, that's why Java language provide support for using lambda expressions only with functional interfaces.

Why do we need functional interface?

An interface with exactly one abstract method is called Functional Interface. @FunctionalInterface annotation is added so that we can mark an interface as functional interface. It is not mandatory to use it, but it's best practice to use it with functional interfaces to avoid addition of extra methods accidentally.

Does lambda expression only work with functional interface?

No, all the lambda expressions in this code implement the BiFunction<Integer, Integer, Integer> function interface. The body of the lambda expressions is allowed to call methods of the MathOperation class. It doesn't have to refer only to methods of a functional interface.


5 Answers

When you write :

TestInterface i = () -> System.out.println("Hans");

You give an implementation to the void hans() method of the TestInterface.

If you could assign a lambda expression to an interface having more than one abstract method (i.e. a non functional interface), the lambda expression could only implement one of the methods, leaving the other methods unimplemented.

You can't solve it by assigning two lambda expressions having different signatures to the same variable (Just like you can't assign references of two objects to a single variable and expect that variable to refer to both objects at once).

like image 107
Eran Avatar answered Oct 12 '22 02:10

Eran


The most important reason why they must contain only one method, is that confusion is easily possible otherwise. If multiple methods were allowed in the interface, which method should a lambda pick if the argument lists are the same ?

interface TestInterface {
    void first();
    void second(); // this is only distinguished from first() by method name
    String third(); // maybe you could say in this instance "well the return type is different"
    Object fourth(); // but a String is an Object, too !
}

void test() {
    // which method are you implementing, first or second ?
    TestInterface a = () -> System.out.println("Ido mein ado mein");
    // which method are you implementing, third or fourth ?
    TestInterface b = () -> "Ido mein ado mein";
}
like image 38
blagae Avatar answered Oct 12 '22 02:10

blagae


You seem to be looking for anonymous classes. The following code works:

public class Test {

    public static void main(String...args) {
        TestInterface i = new TestInterface() {
            public void hans() {
                System.out.println("Hans");
            }
            public void hans(String a) {
                System.out.println(a);
            }
        };

        i.hans();
        i.hans("Hello");
    }
}

public interface TestInterface {
    public void hans();
    public void hans(String a);
}

Lambda expressions are (mostly) a shorter way to write anonymous classes with only one method. (Likewise, anonymous classes are shorthand for inner classes that you only use in one place)

like image 34
user253751 Avatar answered Oct 12 '22 02:10

user253751


You do not have to create a functional interface in order to create lambda function. The interface allow you to create instance for future function invocation.

In your case you could use already existing interface Runable

Runnable r = () -> System.out.println("Hans");

and then call

r.run();

You can think of lambda -> as only short hand for:

Runnable r = new Runnable() {
     void run() {
          System.out.println("Hans");`
     }
}

With lambda you do not need the anonymous class, that is created under the hood in above example.

But this has some limitation, in order to figure out what method should be called interface used with lambdas must be SAM (Single Abstract Method). Then we have only one method.

For more detailed explanation read:

Introduction to Functional Interfaces – A Concept Recreated in Java 8

like image 37
Damian Leszczyński - Vash Avatar answered Oct 12 '22 03:10

Damian Leszczyński - Vash


  • In java when an interface is implemented, all its abstract methods are needed to implemented (otherwise the implementing class will have to be an interface).

  • Java compiler expands lambda expression internally with a class definition with the method, and a statement to instantiate this class. Currently java doesn't support/provide a way for more than 1 lambda to be associated with 1 interface.

      public class Test {
          public static void main(String...args) {
              TestInterface i = () -> System.out.println("Hans"); // this will not compile as the implementation for public void hans(String a); can not be provided/is not found
              //i = (String a) -> System.out.println(a); //this can not add an implementation for 2nd method to i after compilation of 1st lambda
           }
      }
      public interface TestInterface {
          public void hans();
          public void hans(String a);
      }
    

This the reason lambda in java only works with an interface with one method or functional interface.

like image 39
Ach Avatar answered Oct 12 '22 03:10

Ach