Functional Interfaces in Java

Last Updated : 24 Aug 2026

An interface that contains exactly one abstract method is known as a functional interface. It can have any number of default and static methods but can contain only one abstract method. It can also declare methods of the Object class.

Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces. It is a new feature in Java that helps to achieve a functional programming approach.

The introduction of functional interfaces in Java 8 was a game changer, giving developers a more concise and transparent way of writing code. These interfaces paved the way for the adoption of design strategies that work within the Java ecosystem.

Examples of Functional Interfaces

Let's understand functional interfaces with the help of examples.

Example 1: Basic Functional Interface Implementation

In this example, a functional interface is created with one abstract method and implemented in a class.

Java

@FunctionalInterface  
interface Sayable {  
    void say(String msg);  // abstract method
}  
public class Main implements Sayable {  
    public void say(String msg) {  
        System.out.println(msg);  
    }  
    // main method
    public static void main(String[] args) {  
        Main fie = new Main(); // object created 
        fie.say("Hello there");  
    }  
}  
Compile and Run

Output:

Hello there

Explanation

The annotation @FunctionalInterface just above the interface Sayable says that the interface Sayable is a functional interface and hence, it must contain only one abstract method. Violating this rule will lead to a compilation error.

Example 2: Functional Interface with Object Class Methods

In this example, the functional interface includes methods of the Object class along with one abstract method.

Java

@FunctionalInterface  
interface Sayable {  
    void say(String msg);   // only one abstract method  
    // It can contain any number of Object class methods.  
    int hashCode();  
    String toString();  
    boolean equals(Object obj);  
}  
public class Main implements interface Sayable {  {  
    public void say(String msg) {  
        System.out.println(msg);  
    }  
    // main method
    public static void main(String[] args) {  
        Main fie = new Main();  // object created
        fie.say("Hello there");  
    }  
}  
Compile and Run

Output:

Hello there

Invalid Functional Interface

Example: Invalid Functional Interface with Multiple Abstract Methods

A functional interface must contain only one abstract method. If the interface contains more than one abstract method, then it will give a compilation error. The following program shows the same.

Java

interface Sayable {  
    void say(String msg);   // abstract method  
}  
@FunctionalInterface  
interface Doable extends Sayable {  
    // Invalid '@FunctionalInterface' annotation; Doable is not a functional interface  
    void doIt();  // an abstract method
    // It has another abstract method, which is the say () method
    // present in the interface Sayable
}  
public class Main implements Doable {  
    public void say(String msg) {  
        System.out.println(msg);  
    } 
    
    public void doIt() {  
        System.out.println("In the doIt() method.");  
    } 
    // main method
    public static void main(String[] args) {  
        Main fie = new Main();  // object created
        fie.say("Hello there");  
        fie.doIt();  
    }  
}  
Compile and Run

Output:

Compilation Error:
Compilation Error: Main.java:4: error: Unexpected @FunctionalInterface annotation
@FunctionalInterface  
^
  Doable is not a functional interface
    multiple non-overriding abstract methods found in interface Doable
1 error

Note: The above program works fine if we remove the @FunctionalInterface annotation.

Example: Valid Functional Interface Extending Non-Functional Interface

A functional interface can have any number of default methods, static methods, and Object class public methods (such as toString() or equals() method).

Java

interface Doable {  
    default void doIt() {  
        System.out.println("Do it now");  
    }  
}  
@FunctionalInterface  
interface Sayable extends Doable {  
    void say(String msg);   // only one abstract method  
    // It will also have the doIt() method, but it is a default method. Hence, it works.
}  
public class Main implements Sayable {  
    public void say(String msg) {  
        System.out.println(msg);  
    }  
    public static void main(String[] args) {  
        Main fie = new Main();  // object created 
        fie.say("Hello there");  
        fie.doIt();  
    }  
}  
Compile and Run

Output:

Hello there
Do it now

Java Predefined-Functional Interfaces

Java 8 introduced several built-in functional interfaces in the java.util.function package, each designed to support common functional programming patterns. Some of the most commonly used functional interfaces include:

Supplier: Supplier is a built-in functional interface that only provides one output while accepting no arguments or inputs. In the java.util.function.Supplier<T> interface, the get() method is an abstract functional method. It is useful for generating and returning a value without accepting any arguments.

Syntax:

@FunctionalInterface
public interface Consumer {
  void accept(T t);
}
@FunctionalInterface 
public interface Supplier { 
T get(); 
}

Example

import java.util.function.Supplier; 
public class Main { 
    // main method
    public static void main(String[] args) 
    { 
        // Defining a Supplier that will take no arguments and will return a String 
        Supplier var = () -> "Good Morning from Supplier!"; 
        // Executing the supplier with the help of the get() method
        // This statement executes the lambda expression.
        System.out.println(var.get()); 
    } 
}
Compile and Run

Output:

Good Morning from Supplier!

Explanation

The statement () -> "Good Morning from Supplier!" depicts the supplier behavior. It says: "When invoked, return this text." Also, the lambda does not run the code immediately. The statement var.get() calls the method get() present in the Supplier interface. This method invocation actually executes the lambda expression.

Consumer: Consumer is another built-in functional interface in Java that has only one abstract method, which is accept(T t). Its return type is void. An operation that accepts a single input argument and returns no result.

Syntax:

@FunctionalInterface
public interface Consumer {
  void accept(T t);
}

Example

import java.util.function.Consumer;
public class Main {
    // main method
    public static void main(String[] args) {
        // Defining the Consumer for printing string
        Consumer cnsmr = c -> System.out.println(c);
        // Invoking the accept() method
        cnsmr.accept("Good Morning, Consumer!");
        // Defining a Consumer with a Method Reference
        Consumer mthdRefPrinter = System.out::println;
        mthdRefPrinter.accept("Good Morning Consumer method reference! ");
    }
}
Compile and Run

Output:

Good Morning, Consumer!
Good Morning Consumer method reference!

Explanation

The first statement Consumer<String> cnsmr = c -> System.out.println(c); is a Consumer that processes a string. It has a lambda expression that takes the string c as the input and displays it on the console. The cnsmr.accept() invokes the accept method present in the Consumer functional interface, which executes the lambda expression. The second Consumer is similar to the first one, but it has a method reference. Note that mthdRefPrinter = System.out::println; is the replica of the lambda expression mthdRefPrinter = c -> System.out.println(c);

Predicate: Predicate is another built-in functional interface that has an abstract method called test(). The method accepts an argument of type T, and a Boolean value is returned. Predicate interface has other methods too, but they are either default methods or static methods.

Syntax:

@FunctionalInterface
public interface Predicate {
  boolean test(T t);
}

Example

import java.util.function.Predicate;
import java.util.ArrayList;
public class PredicateExample {
    public static void main(String[] args) {
        // creating an array list
        ArrayList al = new ArrayList();
        // adding elements to the array list
        al.add("India");
        al.add("America");
        al.add("Australia");
        al.add("Russia");
        al.add("Finland");
        // Defining a predicate that processes a string. 
        // checks if the string has more than 5 characters or not
        Predicate isLongerThan6 = s -> s.length() > 6;
        for(String str : al)     {
            // invoking the test() method, which in turn executes the
            // lambda expression written above
            System.out.println("Does the string '" + str + "' have more than six characters? " + isLongerThan6.test(str));    
        }
    }
}
Compile and Run

Output:

Does the string 'India' have more than six characters? false
Does the string 'America' have more than six characters? true
Does the string 'Australia' have more than six characters? True
Does the string 'Russia' have more than six characters? false
Does the string 'Finland' have more than six characters? True

Function: In Java 8, Function is another functional interface; it takes an argument and returns an object. The return type and argument may or may not be the same. It has an abstract method apply(). Apart from the abstract method apply(), the Function interface has static and default methods too.

Syntax:

@FunctionalInterface
public interface Function {
      R apply(T t);
}

Example

import java.util.function.Function;
import java.util.ArrayList;
public class Main {
    // main method
    public static void main(String[] args) {
        // creating an array list
        ArrayList al = new ArrayList();
        // adding elements to the array list
        al.add("India");
        al.add("America");
        al.add("Australia");
        al.add("Russia");
        al.add("Finland");
        // Defining a Function that argument type is String, and return type is Integer 
        Function strLen = s -> s.length();
        // Invoking the apply() method
        for(String str : al)    {
            // invoking the apply() method, which in turn executes the
            // lambda expression written above
            System.out.println("The string '" + str + "' has " + strLen.apply(str) + " characters.");    
        }
    }
}
Compile and Run

Output:

The string 'India' has 5 characters.
The string 'America' has 7 characters.
The string 'Australia' has 9 characters.
The string 'Russia' has 6 characters.
The string 'Finland' has 7 characters.

UnaryOperator: UnaryOperator is a functional interface that extends the Function interface.

Syntax:

@FunctionalInterface
public interface UnaryOperator extends Function {
}

Since UnaryOperator is a functional interface, it must have only one abstract method. That method comes from the Function interface. The UnaryOperator interface inherits the apply() method from the Function interface. Here, the return type of the apply() method is also T. Because of this inheritance, the syntax does not mention any explicit method inside the body of the interface.

Example

import java.util.function.UnaryOperator;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
public class Main {
    // main method
    public static void main(String[] args) {
        List numberList = Arrays.asList(11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
        // Inovking the method mathFun(). 
        List res = mathFun(numberList, y -> y * 3);
        System.out.println("The result is: ");
        for( int num : res)
            System.out.print(num + " "); 
    }
    // mathFun() is a static and generic method. It can handle data type of
    // type T. It will return a list of type T. The method takes two arguments
    // is the list and another is UnaryOperator.
    public static  List mathFun(List list, UnaryOperator unryOp) {
        List res = new ArrayList<>();
        for (T l : list) {
            // invokes the method apply(), which excutes the lambda expresssion
            // mentioned above.
            res.add(unryOp.apply(l));
        }
        return res;
    }
}
Compile and Run

Output:

The result is: 
33 36 39 42 45 48 51 54 57 60

BiFunction: BiFunction is another functional interface introduced in Java 8. It has two methods. One is an abstract functional method, apply() that executes the lambda expression, and another is the default method andThen().

Syntax:

@FunctionalInterface 
public interface BiFunction { 
R apply(T t, U u); 
}

T is the type of the first argument, and U is the type of the second argument. R is the return type.

Example

import java.util.function.BiFunction;
public class Main {
    // main method
    public static void main(String[] args) {
        // Here, BiFunction takes two integers and returns a String
        // After multiplication of x and y, it gets converted into a string 
        // as we are concatenating the result with ""
        BiFunction mul = (x, y) -> "" + (x * y);
        int no1 = 15;
        int no2 = 40;
        // invoking the method apply(), which in turn executes 
        // the lambda expression
        String res = mul.apply(no1, no2); 
        System.out.println("Multiplying numbers '" + no1 + "' and '" + no2 + "', result is: "+ res); 
        // BiFunction for adding two integers. 
        // Here, the first and the second argument both 
        // have type Integer, and the return type is also Integer
        BiFunction sum = (a, b) -> a + b;
        // Invoking the apply method to add two numbers by executing 
        // the lambda expression
        int output = sum.apply(no1, no2);
        System.out.println("Adding numbers '" + no1 + "' and '" + no2 + "', result is: "+ output);
    }
}
Compile and Run

Output:

Output:
Multiplying numbers '15' and '40', result is: 600
Adding numbers '15' and '40', result is: 55

BinaryOperator: BinaryOperator is another built-in functional interface introduced in Java 8. This interface extends the BiFunction interface. Thus, the abstract fuctional method apply() present in the BiFunction interface gets copied to the BinaryOperator interface because of inhertance.

Syntax:

@FunctionalInterface 
public interface BiFunction { 
}

T is the type of the first argument, T is the type of the second argument. T is also the return type.

Example

import java.util.function.BinaryOperator;
import java.util.List;
import java.util.Arrays;
public class Main {
    public static void main(String[] args) {        
        // array of integers
        Integer[] numArr = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
        // Invoking the method mathSum(). It has three arguments.
        // The lambda expression adds the two integers x and y
        Integer sum = mathSum(Arrays.asList(numArr), 0, (x, y) -> x + y);
        System.out.print("For the numbers: ");
        for( var k : numArr)      {
            System.out.print(k + " ");
        }
        System.out.println();
        System.out.println("The total is: " + sum); 
    }
    // mathSum() is a generic method. It has type T. 
    // Its first argument is a list of type T.
    // The second argument is a value init of type T.
    // The third argument is a BinaryOperator
    // In this program, T is of type Integer
    public static  T mathSum(List list, T init, BinaryOperator bo) {
        T res = init; //res is initialized with the value init
        // looping through the list
        for (T k : list) {
           // invoking the method apply(), which in turn executes the 
           // lambda expression to add two numbers res and k
           res = bo.apply(res, k);
        }
        return res;
    }
}
Compile and Run

Output:

For the numbers: 11 12 13 14 15 16 17 18 19 20 
The total is: 155

These functional interfaces provide a foundation for writing functional-style code in Java. They encapsulate common patterns and enable developers to write more concise and readable code.

List of Functional Interfaces

We can also define our own custom functional interface. The following is the list of functional interfaces that belong to java.util.function package

InterfaceDescription
BiConsumer<T,U>It represents an operation that accepts two input arguments and returns no result.
Consumer<T>It represents an operation that accepts a single argument and returns no result.
Function<T,R>It represents a function that accepts one argument and returns a result.
Predicate<T>It represents a predicate (boolean-valued function) of one argument.
BiFunction<T,U,R>It represents a function that accepts two arguments and returns a a result.
BinaryOperator<T>It represents an operation upon two operands of the same data type. It returns a result of the same type as the operands.
BiPredicate<T,U>It represents a predicate (boolean-valued function) of two arguments.
BooleanSupplierIt represents a supplier of boolean-valued results.
DoubleBinaryOperatorIt represents an operation upon two double type operands and returns a double type value.
DoubleConsumerIt represents an operation that accepts a single double type argument and returns no result.
DoubleFunction<R>It represents a function that accepts a double type argument and produces a result.
DoublePredicateIt represents a predicate (boolean-valued function) of one double type argument.
DoubleSupplierIt represents a supplier of double type results.
DoubleToIntFunctionIt represents a function that accepts a double type argument and produces an int type result.
DoubleToLongFunctionIt represents a function that accepts a double type argument and produces a long type result.
DoubleUnaryOperatorIt represents an operation on a single double type operand that produces a double type result.
IntBinaryOperatorIt represents an operation upon two int type operands and returns an int type result.
IntConsumerIt represents an operation that accepts a single integer argument and returns no result.
IntFunction<R>It represents a function that accepts an integer argument and returns a result.
IntPredicateIt represents a predicate (boolean-valued function) of one integer argument.
IntSupplierIt represents a supplier of integer type.
IntToDoubleFunctionIt represents a function that accepts an integer argument and returns a double.
IntToLongFunctionIt represents a function that accepts an integer argument and returns a long.
IntUnaryOperatorIt represents an operation on a single integer operand that produces an integer result.
LongBinaryOperatorIt represents an operation upon two long type operands and returns a long type result.
LongConsumerIt represents an operation that accepts a single long type argument and returns no result.
LongFunction<R>It represents a function that accepts a long type argument and returns a result.
LongPredicateIt represents a predicate (boolean-valued function) of one long type argument.
LongSupplierIt represents a supplier of long type results.
LongToDoubleFunctionIt represents a function that accepts a long type argument and returns a result of double type.
LongToIntFunctionIt represents a function that accepts a long type argument and returns an integer result.
LongUnaryOperatorIt represents an operation on a single long type operand that returns a long type result.
ObjDoubleConsumer<T>It represents an operation that accepts an object and a double argument, and returns no result.
ObjIntConsumer<T>It represents an operation that accepts an object and an integer argument. It does not return result.
ObjLongConsumer<T>It represents an operation that accepts an object and a long argument, it returns no result.
Supplier<T>It represents a supplier of results.
ToDoubleBiFunction<T,U>It represents a function that accepts two arguments and produces a double type result.
ToDoubleFunction<T>It represents a function that returns a double type result.
ToIntBiFunction<T,U>It represents a function that accepts two arguments and returns an integer.
ToIntFunction<T>It represents a function that returns an integer.
ToLongBiFunction<T,U>It represents a function that accepts two arguments and returns a result of long type.
ToLongFunction<T>It represents a function that returns a result of long type.
UnaryOperator<T>It represents an operation on a single operand that returnsa a result of the same type as its operand.

Next TopicJava 8 Stream