Functional Interface is a regular interface with only one abstract method. But it can have any number of default methods as they are not abstract method.
Also, if an functional interface redeclare any method from java.lang.Object class, it will get the implementation of method from somewhere. So it will also not count as abstract method.
@FunctionalInterface interface Shape { void createShape(); }
Creating Instance of Functional Interface:
We can create an instance of Functional interface same as any Interface using anonymous class.
public class Test { public static void main(String[] args) { Shape shape = new Shape() { @Override public void createShape() { System.out.println("creating shape"); } }; shape.createShape(); } }
The above mentioned way is traditional way of creating instance of interface, but it has a lot of boilerplate code. we can achieve the same functionality using one of the below:
Lambda expression:
public class Test { public static void main(String[] args) { Shape shape = () -> System.out.println("creating shape"); shape.createShape(); } }
Method reference:
Some time lambda expression just call another method from inside.
public class Test { // 1 public static void main(String[] args) { // 2 Shape shape = (shapeType) -> printMg(shapeType); // 3 shape.createShape("circle"); // 4 } // 5 // 6 public static void printMg(String shapeType) { // 7 System.out.println("creating " + shapeType); // 8 } // 9 } // 10
In above example, we created an instance of the interface Shape using lambda expression. inside the implementation it is only calling printMsg() method. We can replace it using Method Reference.
public static void main(String[] args) { // 2 Shape shape = Test::printMg; // 3 shape.createShape("circle"); // 4 }
Constructor reference:
Imagine we want to create a new object of class Test inside the implementation of Shape interface. we can do it using lambda as following:
public class Test { // 1 public static void main(String[] args) { // 2 Shape shape = (shapeType) -> new Test(shapeType); // 3 shape.createShape("circle"); // 4 } // 5 public Test(String shapeType) { // 6 System.out.println("creating " + shapeType); // 7 } // 8 } // 9
We can replace the lambda expression in line no 4 with constructor reference as below:
public static void main(String[] args) { // 2 Shape shape = Test::new; // 3 shape.createShape("circle"); // 4 }
Rules for using @FunctionalInterface annotation:
- If an interface is annotated with @FunctionalInterface and have more than one abstract method, it will cause compilation error.
- If @FunctionalInterface annotation is used with class or enum it will show compilation error.
- Even if an Interface is not annotated with @FunctionalInterface and have only one abstract method, compiler will treat it as functional interface.
Benefit of using functional interface:
- Instead of anonymous class, lambda expression can be used for instance creation.
- When we create an instance using lambda expression, the compiler will not create any separate class file, as it does for anonymous classes. So the code base will be lighter and run faster.
- Compiler will use Invokedynamic to create the object, which is instantiated by lamba expression.
Its really very nicely explained.