In Java, functional interfaces are those interfaces who has exactly one abstract method.  @FunctionalInterface is not a mandatory annotation to be used to make any interface a Functional Interface. Its just an informative annotation type used to indicate that an interface type declaration is intended to be a functional interface. Since default methods have an implementation, they are not abstract.

Note: – If an interface declares any method of java.lang.Object class as abstract then that abstract method wont be treated as abstract because any implementation of the interface will have an implementation from java.lang.Object or elsewhere.

i.e.

//RIGHT. No Compilation issue
@FunctionalInterface
public interface Square {
   abstract int doDouble(int number); 
   abstract String toString(); //toString() method is coming from Object class
}

//WRONG. More than 1 abstract methods not allowed.
@FunctionalInterface
public interface Square {
 abstract int doDouble(int number); 
 abstract int doTriple(int num); 
}

//RIGHT. But its no more a Functional Interface
public interface Square {
 abstract int doDouble(int number); 
 abstract int doTriple(int num); 
}

 

The instances of functional interfaces can be created with lambda expressions, method references, or constructor references. 

Lets have below interface as an example:


@FunctionalInterface
public interface Square {
    int doSquare(int number); 
}

 

  • Using Lambdas

Square square = (int x) -> x*x; 
System.out.println(square.doSquare(5));

or

int x = 10;
System.out.println(test.sayHello(x, (value) -> value * value));

 

  • Using Method References

public static void main(String[] args) {
    int x = 10;
    Square s = new SquareImpl(); 
    print(s::doSquare, x); 
}

public static void print(Function<Long, Long> function, Long value) { 
    System.out.println(function.apply(value)); 
}

Here we defined print() function to use the java.util.function.Function interface. In this case, the Function instance passed to print() has its apply() method implemented to return square of the value passed.

 

  • Using Constructor references

@FunctionalInterface
public interface EmployeeProvider { 
    Employee getEmployee(String name, Integer salary);
}

class Employee{
  String name;
  Integer age;

  Employee(String name, Integer age){
    this.name = name;
    this.age = age;
  }
}

// Constructor Way 
EmployeeProvider provider = Employee::new; 
Employee emp = provider.getEmployee("John Doe", 34000); 
System.out.printf("Name: %s%n", emp.getName()); 
System.out.printf("Age: %d%n", emp.getSalary());

When it encounters Employee::new, the compiler infers the right constructor to call based on the context in which the constructor reference appears. Here,  the  EmployeeProvider provider provides this context. Because this functional interface supplies a single abstract method whose parameter list matches the second Employee constructor, the compiler chooses that constructor. The constructor is then called (and the Employee object returned) by the subsequent getEmployee() method call.

However, remember that 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.

 

GIT Url : https://github.com/tektutorial/java-design/tree/master/src/com/tektutorial/funcinterface

 

Hope this clears your doubt!!