Introduction
Java 8 introduced the concept of functional interfaces, which are interfaces with a single abstract method. These interfaces can be implemented using lambda expressions, making them a key component of functional programming in Java. While Java 8 provides several built-in functional interfaces like Function, Predicate, and Supplier, there are scenarios where you might need a custom functional interface tailored to your specific use case.
In this guide, we’ll explore how to create a custom functional interface in Java 8, along with examples demonstrating its use with lambda expressions.
Table of Contents
- Problem Statement
- Solution Steps
- Java Program
- Example 1: Creating a Simple Custom Functional Interface
- Example 2: Using a Custom Functional Interface with Lambda Expressions
- Example 3: Extending a Custom Functional Interface
 
- Conclusion
Problem Statement
In certain cases, the built-in functional interfaces provided by Java 8 might not fit the specific needs of your application. The goal is to create a custom functional interface that can be implemented using lambda expressions, allowing you to define and reuse specific functional behavior.
Example:
- Problem: You need an interface that accepts two integers and returns a boolean indicating whether the first is greater than the second.
- Goal: Create a custom functional interface that fits this requirement and demonstrate how to use it with lambda expressions.
Solution Steps
- Define a Functional Interface: Create an interface with a single abstract method annotated with @FunctionalInterface.
- Use Lambda Expressions to Implement the Interface: Implement the interface using lambda expressions to define custom behavior.
- Extend the Functional Interface: Optionally, extend the custom functional interface to add default or static methods.
Java Program
Example 1: Creating a Simple Custom Functional Interface
First, let’s define a simple custom functional interface that takes two integers and returns a boolean value.
/**
 * Java 8 - How to Create a Custom Functional Interface
 * Author: https://www.rameshfadatare.com/
 */
@FunctionalInterface
public interface IntegerComparator {
    boolean compare(int a, int b);
}
Explanation
- @FunctionalInterface: This annotation is optional but recommended as it indicates that the interface is intended to be a functional interface. It ensures that the interface cannot have more than one abstract method.
- Single Abstract Method: The comparemethod takes two integers and returns a boolean value, making this interface a functional interface.
Example 2: Using a Custom Functional Interface with Lambda Expressions
Now that we have our custom functional interface, let’s implement it using a lambda expression.
public class CustomFunctionalInterfaceExample {
    public static void main(String[] args) {
        // Using lambda expression to implement the custom functional interface
        IntegerComparator isGreater = (a, b) -> a > b;
        // Test the lambda expression
        int x = 10;
        int y = 5;
        boolean result = isGreater.compare(x, y);
        System.out.println(x + " is greater than " + y + ": " + result);
    }
}
Output
10 is greater than 5: true
Explanation
- Lambda Expression: The lambda expression (a, b) -> a > bprovides an implementation for thecomparemethod, making the code concise and easy to read.
- Testing the Implementation: The comparemethod is called with two integers, and the result is printed, demonstrating that the custom functional interface works as expected.
Example 3: Extending a Custom Functional Interface
You can extend the functionality of your custom functional interface by adding default or static methods.
@FunctionalInterface
public interface ExtendedIntegerComparator {
    boolean compare(int a, int b);
    // Default method to check if two integers are equal
    default boolean isEqual(int a, int b) {
        return a == b;
    }
    // Static method to compare two integers using a lambda
    static boolean isLessThan(int a, int b) {
        return a < b;
    }
}
public class ExtendedFunctionalInterfaceExample {
    public static void main(String[] args) {
        // Using lambda expression to implement the custom functional interface
        ExtendedIntegerComparator isGreater = (a, b) -> a > b;
        // Test the lambda expression
        int x = 10;
        int y = 5;
        System.out.println(x + " is greater than " + y + ": " + isGreater.compare(x, y));
        // Test the default method
        System.out.println(x + " is equal to " + y + ": " + isGreater.isEqual(x, y));
        // Test the static method
        System.out.println(x + " is less than " + y + ": " + ExtendedIntegerComparator.isLessThan(x, y));
    }
}
Output
10 is greater than 5: true
10 is equal to 5: false
10 is less than 5: false
Explanation
- Default Method: The isEqualmethod provides additional functionality to the interface without requiring implementation in the lambda expression.
- Static Method: The isLessThanmethod is a utility function that can be used independently of an instance of the interface.
- Extended Functionality: This example shows how to enhance a custom functional interface by adding more utility methods, making it more versatile.
Conclusion
Creating a custom functional interface in Java 8 allows you to define and encapsulate specific functional behaviors that may not be covered by the built-in interfaces. By using the @FunctionalInterface annotation and lambda expressions, you can create concise and reusable code. Extending these interfaces with default and static methods further enhances their functionality, making them powerful tools in your Java development toolkit.