In this article, we will discuss about new features introduced in Java 1.8 version i.e.; Functional Interface
Q) What is Functional Interface ?
- An interface which contains only one abstract method is called as Functional interface
Q) 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
1. 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
2. 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
ParentInterface.java
package net.bench.resources.java8;
@FunctionalInterface
public interface ParentInterface {
public void display();
}
2.1 Valid scenario 1:
ChildInterface.java
@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
2.2 Valid Scenario 2:
ChildInterface.java
@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
2.3 Valid Scenario 3:
ChildInterface.java
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
2.4 Invalid scenario 1:
ChildInterface.java
@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
3. Example for Functional Interface along with Lambda Expression:
3.1 To find cube of any Integer
TestLambdaExpression.java
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
3.2 To multiply any two Integer
TestLambdaExpression.java
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
3.3 To find substring of last 3 characters
TestLambdaExpression.java
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
3.4 To print Hello World
TestLambdaExpression.java
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)
- Pre-defined Functional Interface (2 arguments)
- 1. BiPredicate
- 2. BiFunction
- 3. BiConsumer
- Primitive Predicate Functional Interface
- 1. IntPredicate
- 2. LongPredicate
- 3. DoublePredicate
- Primitive Function Functional Interface
- 1.1 IntFunction
- 1.2 LongFunction
- 1.3 DoubleFunction
- 2.1 ToIntFunction
- 2.2 ToLongFunction
- 2.3 ToDoubleFunction
- 3.1 IntToLongFunction
- 3.2 IntToDoubleFunction
- 3.3 LongToIntFunction
- 3.4 LongToDoubleFunction
- 3.5 DoubleToIntFunction
- 3.6 DoubleToLongFunction
- Primitive BiFunction Functional Interface
- 1. ToIntBiFunction
- 2. ToLongBiFunction
- 2. ToDoubleBiFunction
- Primitive Consumer Functional Interface
- 1.1 IntConsumer
- 1.2 LongConsumer
- 1.3 DoubleConsumer
- 2.1 ObjIntConsumer
- 2.2 ObjLongConsumer
- 2.3 ObjDoubleConsumer
- Primitive Supplier Functional Interface
- 1. IntSupplier
- 2. LongSupplier
- 3. DoubleSupplier
- 4. BooleanSupplier
- UnaryOperator Functional Interface and its primitive types
- 1. IntUnaryOperator
- 2. LongUnaryOperator
- 3. DoubleUnaryOperator
- BinaryOperator Functional Interface and its primitive types
- 1. IntBinaryOperator
- 2. LongBinaryOperator
- 3. DoubleBinaryOperator
References:
- https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
- https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html
- https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
- https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
Happy Coding !!
Happy Learning !!