Java 8 – Functional Interface in Java

In this article, we will discuss about new features introduced in Java 1.8 version i.e.; Functional Interface

What is Functional Interface ?

  • An interface which contains only one abstract method is called as Functional interface

Why we need Functional Interface ?

  • Another feature introduced in Java 1.8 version is Lambda Expression
  • To invoke/call this lambda expression we need Functional Interface

Rules for Functional Interface :

  • As mentioned earlier above, Functional Interface can have maximum of only one abstract method
  • In short, it is called as Single Abstract Method i.e.; SAM
  • In addition to one abstract method, we can have any number of static or default methods, another feature added in Java 1.8 version
  • An optional annotation @FunctionalInterface can be annotated for Functional Interface to make sure that not more than one abstract method is declared
  • If more than one abstract method declared and also annotated with @FunctionalInterface, then compiler throws error
  • Note: To invoke Lambda Expression we need Functional Interface and it is must

Few valid and invalid scenarios w.r.t Inheritance

Let us understand with example for Functional Interface

  • ParentInterface is valid because we have only one abstract method declared
  • So, here we are checking/verifying valid/invalid scenarios for ChildInterface
package net.bench.resources.java8;

@FunctionalInterface
public interface ParentInterface {

	public void display();
}

Valid scenario 1:

@FunctionalInterface
interface ChildInterface extends ParentInterface{
	// no more abstract methods declared

       // any number of static and default methods
}
  • ChildInterface inherits but no more abstract method is declared
  • But can have any number of static and default methods
  • Note: Both parent interface & child interface is annotated with @FunctionalInterface

Valid Scenario 2:

@FunctionalInterface
interface ChildInterface extends ParentInterface{
	
	// same abstract methods re-declared
	public void display();
	
	// any number of static and default methods
}
  • ChildInterface inherits but same abstract method is re-declared
  • But can have any number of static and default methods
  • Note: Both parent interface & child interface is annotated with @FunctionalInterface

Valid Scenario 3:

interface ChildInterface extends ParentInterface{
	
	// one more abstract method declared
	public void sum();
	
	// any number of static and default methods
}
  • There is no @FunctionalInterface annotation in ChildInterface
  • Therefore it will act as normal interface in Java with additional abstract methods
  • Note: Only parent interface annotated with @FunctionalInterface so we can add any number of abstract methods in child interface as there is no @FunctionalInterface annotation

Invalid scenario 1:

@FunctionalInterface
interface ChildInterface extends ParentInterface{
	
	// one more abstract method declared
	public void sum();
	
	// any number of static and default methods
}
  • Compile time error – Invalid ‘@FunctionalInterface’ annotation; ChildInterface is not a functional interface
  • Now ChildInterface contains 2 methods, one inherited from ParentInterface and another declared in ChildInterface
  • Note: Both parent interface & child interface is annotated with @FunctionalInterface

Example for Functional Interface along with Lambda Expression:

Example 1: To find cube of any Integer

package net.bench.resources.java8;

@FunctionalInterface
interface DemoInterface {
	public int cube(int i);
}

public class TestLambdaExpression {

	// main method
	public static void main(String[] args) {

		// Lambda Expression
		DemoInterface d = (i) -> i*i*i;

		// how to invoke Lambda Expression -> Functional Interface
		System.out.println(d.cube(7));
	}
}

Output:

343

Example 2: To multiply any two Integer

package net.bench.resources.java8;

@FunctionalInterface
interface DemoInterface {
	public int multiply(int i, int j);
}

public class TestLambdaExpression {

	// main method
	public static void main(String[] args) {

		// Lambda Expression
		DemoInterface d = (i, j) -> i*j;

		// how to invoke Lambda Expression -> Functional Interface
		System.out.println(d.multiply(7, 21));
	}
}

Output:

147

Example 3: To find substring of last 3 characters

package net.bench.resources.java8;

@FunctionalInterface
interface DemoInterface {
	public String substring(String s);
}

public class TestLambdaExpression {

	// main method
	public static void main(String[] args) {

		// Lambda Expression
		DemoInterface d = (s) -> s.substring((s.length()-3), s.length());

		// how to invoke Lambda Expression -> Functional Interface
		System.out.println(d.substring("BenchResources.Net"));
	}
}

Output:

Net

Example 4: To print Hello World

package net.bench.resources.java8;

@FunctionalInterface
interface DemoInterface {
	public void print();
}

public class TestLambdaExpression {

	// main method
	public static void main(String[] args) {

		// Lambda Expression
		DemoInterface d = () -> System.out.println("Hello World");;

		// how to invoke Lambda Expression -> Functional Interface
		d.print();
	}
}

Output:

Hello World

So far, whatever Functional Interface we have seen is all custom for our purposes. In this way, we will creating lot of redundant code whose purpose will be very similar. To address this, Java 1.8 version comes with couple of Pre-defined Functional Interface as listed below,

  • Pre-defined Functional Interface (1 argument)
    1. Predicate
    2. Function
    3. Consumer
    4. Supplier
  • Pre-defined Functional Interface (2 arguments)
    1. BiPredicate
    2. BiFunction
    3. BiConsumer
  • Primitive Predicate Functional Interface
  • Primitive Function Functional Interface
  • Primitive Consumer Functional Interface
  • Primitive Supplier Functional Interface
  • UnaryOperator Functional Interface
  • BinaryOperator Functional Interface

References:

Happy Coding !!
Happy Learning !!

Java 8 - Anonymous Inner class v/s Lambda Expression
Java 8 - Lambda Expression