32

In Java 8 the lambda expression is introduced to help with the reduction of boilerplate code. If the interface has only one method it works fine. If it consists of multiple methods, then none of the methods work. How can I handle multiple methods?

We may go for the following example

public interface I1()
{
    void show1();
    void show2();
}

Then what will be the structure of the main function to define the methods in the main itself?

Mathieu K.
  • 283
  • 3
  • 14
Soumya Kanti Naskar
  • 1,021
  • 3
  • 16
  • 29

4 Answers4

37

Lambda expressions are only usable with functional interface as said by Eran but if you really need multiple methods within the interfaces, you may change the modifiers to default or static and override them within the classes that implement them if necessary.

public class Test {
    public static void main(String[] args) {
        I1 i1 = () -> System.out.println(); // NOT LEGAL
        I2 i2 = () -> System.out.println(); // TOTALLY LEGAL
        I3 i3 = () -> System.out.println(); // TOTALLY LEGAL
    }
}

interface I1 {
    void show1();
    void show2();
}

interface I2 {
    void show1();
    default void show2() {}
}

interface I3 {
    void show1();
    static void show2 () {}
}

Inheritance

You shouldn't forget the inherited methods.

Here, I2 inherits show1 and show2 and thus can not be a functional interface.

public class Test {
    public static void main(String[] args) {
        I1 i1 = () -> System.out.println(); // NOT LEGAL BUT WE SAW IT EARLIER
        I2 i2 = () -> System.out.println(); // NOT LEGAL
    }
}

interface I1 {
    void show1();
    void show2();
}

interface I2 extends I1 {
    void show3();
}

Annotation

To make sure your interface is a functional interface, you may add the following annotation @FunctionalInterface

@FunctionalInterface <------- COMPILATION ERROR : Invalid '@FunctionalInterface' annotation; I1 is not a functional interface
interface I1 {
    void show1();
    void show2();
}

@FunctionalInterface
interface I2 {
    void show3();
}
Yassin Hajaj
  • 21,337
  • 9
  • 51
  • 89
14

Lambda expressions can only be used to implement functional interfaces, which are interfaces having a single abstract method. An interface with two abstract methods can't be implemented by a lambda expression.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • 1
    You also have to add the @FunctionalInterface annotation to the interface (https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html) and the compiler checks if there is only one method in the interface. – Martin Mar 26 '16 at 09:08
  • So is there any other alternative to remove the boilerplate codes just as in the Lambda Expression ? – Soumya Kanti Naskar Mar 26 '16 at 09:10
  • 4
    @MartinKrüger You can add that annotation, but you don't have to. The compiler will treat any interface meeting the definition of a functional interface as a functional interface regardless of whether or not a FunctionalInterface annotation is present on the interface declaration – Eran Mar 26 '16 at 09:12
  • 4
    @MartinKrüger You do not _have_ to add the `@FunctionalInterface` annotation to use the interface as a lambda. Although it helps as a marker to indicate that this will only have a single abstract method. – marstran Mar 26 '16 at 09:13
  • 1
    @SoumyaKantiNaskar Not unless you give default implementations to all the methods in your interface except one. – Eran Mar 26 '16 at 09:14
14

I usually create a static factory method directly in the interface:

public inteface I1 {
    void show1();
    void show2();

    public static I1 of(Runnable show1, Runnable show2) {
        return new I1() {
            void show1() { show1.run(); }
            void show2() { show2.run(); }
        };
    }
}

Usage:

I1 i1 = I1.of(() -> System.out.println("show1"), () -> System.out.println("show2"));
Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
4

You can always use composition:

public inteface I1 {
    void show1();
    void show2();
}

public class I1Adapter {
    private final Runnable r1,r2;
    public I1Adapter(Runnable r1, Runnable r2) {this.r1=r1; this.r2=r2;}
    public void show1() {r1.run();}
    public void show2() {r2.run();}
    public static I1Adapter compose(Runnable r1, Runnable r2) {
        return new I1Adapter(r1,r2);
    }
}

No you can do (with a static import):

I1 i1 = compose(()->foo(), ()->bar());
Tassos Bassoukos
  • 16,017
  • 2
  • 36
  • 40