A functional interface in Java is an interface that has exactly one abstract method (SAM – Single Abstract Method).
- They may have any number of default or static methods.
- Functional interfaces are the foundation of lambda expressions and method references (introduced in Java 8).
@FunctionalInterface
(optional but recommended).
You can create your own functional interfaces to suit business logic.
Example 1: Custom Greeting Interface
Output:
Example 2: Calculator Interface
Output:
Example 3: String Formatter Interface
Output:
Java provides many ready-to-use functional interfaces inside the java.util.function
package.
Categories of Built-in Functional Interfaces:
-
Core Function Types
-
Predicate<T>
– Tests a condition, returnsboolean
. -
Function<T, R>
– Converts inputT
to outputR
. -
Consumer<T>
– Accepts a value, returns nothing. -
Supplier<T>
– Produces a value, takes no input.
-
-
Multi-Argument & Same-Type Variants
-
BiPredicate<T, U>
– Tests two inputs, returnsboolean
. -
BiFunction<T, U, R>
– Function with two inputs. -
BiConsumer<T, U>
– Consumes two inputs, no return. -
UnaryOperator<T>
– Operation on one input (same type). -
BinaryOperator<T>
– Operation on two inputs (same type).
-
-
Primitive Specializations
-
For performance, avoid boxing/unboxing.
-
IntPredicate
,LongPredicate
,DoublePredicate
-
IntFunction
,IntConsumer
,IntSupplier
-
IntUnaryOperator
,IntBinaryOperator
, etc.
-
-
Advanced Function Interfaces
-
ObjIntConsumer<T>
,ObjLongConsumer<T>
,ObjDoubleConsumer<T>
-
ToIntFunction<T>
,ToDoubleFunction<T>
, etc. -
ToDoubleBiFunction<T, U>
, etc.
-
-
Other JDK Functional Interfaces
-
Runnable
(method:run()
) -
Callable<V>
(method:call()
) -
Comparable<T>
(method:compareTo()
) -
Event Listeners (
ActionListener
,FileFilter
, etc.)
-
๐น Examples of Built-in Functional Interfaces
1. Core Interfaces
Predicate<T>
Output: true
Function<T, R>
Output: 5
Supplier<T>
Output: 0.65784...
Consumer<T>
Output: Message: Hello Functional Interfaces!
2. Bi- & Same-Type Interfaces
BiPredicate<T, U>
Output: true
BiFunction<T, U, R>
Output: 12
BiConsumer<T, U>
Output: Hi Hi Hi
UnaryOperator<T>
Output: 36
BinaryOperator<T>
Output: 20
3. Primitive Specializations
IntPredicate
Output: false
IntUnaryOperator
Output: 27
DoubleSupplier
Output: 3.141592653589793
ObjIntConsumer<T>
Output: r
4. Converters
ToIntFunction<T>
Output: 5
ToDoubleBiFunction<T, U>
Output: 15.0
5. Other JDK Functional Interfaces
Runnable
Output: Running in thread!
Callable<V>
Output: Result from Callable
Comparable<T>
Category | Interface | Method (SAM) | Description | Example |
Core | Predicate<T> | boolean test(T t) | Returns true/false | Predicate<Integer> isEven = n -> n % 2 == 0; isEven.test(10); // true |
Function<T,R> | R apply(T t) | Converts input to output | Function<String,Integer> len = s -> s.length(); len.apply("Siraj"); // 5 | |
Supplier<T> | T get() | Supplies a value | Supplier<Double> rnd = () -> Math.random(); rnd.get(); | |
Consumer<T> | void accept(T t) | Consumes value, no return | Consumer<String> print = m -> System.out.println(m); print.accept("Hi"); | |
Bi- & Same-Type | BiPredicate<T,U> | boolean test(T t,U u) | Tests 2 inputs | BiPredicate<String,Integer> longer = (s,l) -> s.length()>l; |
BiFunction<T,U,R> | R apply(T t,U u) | Function with 2 inputs | BiFunction<Integer,Integer,Integer> add = (a,b)->a+b; | |
BiConsumer<T,U> | void accept(T t,U u) | Consumes 2 inputs | BiConsumer<String,Integer> repeat = (w,t)->{for(int i=0;i<t;i++) System.out.print(w+" ");}; | |
UnaryOperator<T> | T apply(T t) | Operation on single value, same type | UnaryOperator<Integer> square = x->x*x; | |
BinaryOperator<T> | T apply(T t1,T t2) | Operation on 2 same type | BinaryOperator<Integer> multiply = (a,b)->a*b; | |
Primitive Specializations | IntPredicate | boolean test(int) | Predicate for int | IntPredicate pos = n->n>0; pos.test(-5); // false |
IntUnaryOperator | int applyAsInt(int) | Unary op on int | IntUnaryOperator cube = x->x*x*x; cube.applyAsInt(3); // 27 | |
DoubleSupplier | double getAsDouble() | Supplies double | DoubleSupplier pi = ()->Math.PI; pi.getAsDouble(); | |
ObjIntConsumer<T> | void accept(T t,int v) | Consumes object + int | ObjIntConsumer<String> printer = (s,i)->System.out.println(s.charAt(i)); printer.accept("Siraj",2); // r | |
Converters | ToIntFunction<T> | int applyAsInt(T t) | Converts to int | ToIntFunction<String> len = s->s.length(); len.applyAsInt("India"); // 5 |
ToDoubleBiFunction<T,U> | double applyAsDouble(T t,U u) | 2 inputs → double | ToDoubleBiFunction<Integer,Integer> avg = (a,b)->(a+b)/2.0; | |
Other JDK Functional Interfaces | Runnable | void run() | Task with no args, no result | Runnable task = ()->System.out.println("Running"); new Thread(task).start(); |
Callable<V> | V call() | Task with result | Callable<String> call = ()->"Result"; call.call(); | |
Comparable<T> | int compareTo(T o) | Defines natural ordering | class P implements Comparable<P>{int age;P(int a){age=a;} public int compareTo(P o){return age-o.age;}} |
In Short:
-
Functional Interface = 1 abstract method
-
Foundation of Lambda Expressions & Streams
-
Many built-in interfaces in
java.util.function
-
You can also create custom functional interfaces for business logic
Diagram: How a Lambda Expression Implements a Functional Interface
๐ A lambda (x) -> ...
is nothing but a shortcut implementation of the functional interface method.
Example Code:
Diagram:
๐ Each step uses a different built-in functional interface:
-
filter
→Predicate<T>
-
map
→Function<T, R>
-
forEach
→Consumer<T>
Diagram: Categories of java.util.function Interfaces
Example Code:
Diagram:
Before (Java 7 Style):
After (Java 8 Lambda):
Diagram:
These diagrams make it easier to visualize:
-
How functional interfaces map to lambdas
-
How they are used in Streams
-
How Java internally treats them