Technical architectural analysis, practical configuration manifests, and deployment instructions for Java Functional Interfaces & Lambda.
Overview
A functional interface is an interface with one abstract method.
Starting from Java8, interfaces can contain default methods with default implementations.
Even if there are multiple default methods, if there is only one abstract method, it is a functional interface.
Lambda expressions in Java can only be used as functional interfaces.
1. Functional Interface
As explained above, a functional interface refers to an interface with only one abstract method.
One abstract method means that there may be multiple default method or static method.
And we use the @FunctionalInterface annotation, which checks whether the interface meets the conditions for a functional interface.
@FunctionalInterface There is no problem in operating and using the functional interface without the annotation, but it is recommended to attach it for interface verification and maintenance.
1.1. Why is it needed?
A functional interface is a general term for an interface in which only one abstract method is defined. The purpose of this interface type is to implement functional programming using Lambda ExpressionVisit Website in Java.
But if you think about it carefully, the form (signature) of the function is diverse. The function may or may not have a return value, and the number of parameters may be one or two. Since there are too many functions to define and use these types of functions individually, Java developers create and provide functional interfaces in advance, which is the functional interface standard API that we will learn in this lesson.
1.2. Functional Interface Example
@FunctionalInterface
interface CustomInterface<T> {
// abstract method ์ค์ง ํ๋T myCall();
// default method ๋ ์กด์ฌํด๋ ์๊ด์์default void printDefault() {
System.out.println("Hello Default");
}
// static method ๋ ์กด์ฌํด๋ ์๊ด์์static void printStatic() {
System.out.println("Hello Static");
}
}
The above interface is a functional interface.
There is no problem even if you add default method, static method.
If it does not fit the functional interface format anyway, @FunctionalInterface will display the following error.
2. Functional Interfaces provided by Java
| functional interface | Descriptor | Method | Method type | API usage | Parameters | Return value |
|
Predicate\ |
T -> boolean
|
boolean test(T t)
|
boolean test(T t) | Determines whether the parameter value meets the conditions and returns a boolean | O | O |
|
Consumer\ |
T -> void
|
void accept(T t)
|
void accept(T t) | Used as a function that only uses parameters and does not return | O | X |
|
Supplier\ |
() -> T
|
T get()
|
T get() | Used as a function that does not use parameters and only returns | X | O |
|
Function\ |
T -> R
|
R apply(T t)
|
R apply(T t) | Mapping (=type conversion) the parameter value and returning it | O | O |
| Comparator |
(T, T) -> int
|
int compare(T o1, T o2)
|
||||
| Runnable |
() -> void
|
void run()
|
void run() | Used in the form of a function that does not use parameters and does not return. Typically used as a thread parameter. | X | X |
| Callable |
() -> T
|
V call()
|
||||
| Operator |
T -> R
|
R applyAs(T t) | Calculating parameters and returning results | O | O |
2.1. Predicate
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
Predicate takes one argument and returns a boolean type.
In lambda expression, it is expressed as T -> boolean.
2.2. Consumer
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
Consumer takes one argument and returns nothing.
In a lambda expression, it is expressed as T -> void.
Befitting the name consumer, you can think of it as receiving something (a factor) and just consuming it.
2.3. Supplier
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Supplier takes no arguments and returns an object of type T.
In lambda expression, it is expressed as () -> T.
As the name provider suggests, it takes nothing and returns a specific object.
2.4. Function
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
Function takes a T type argument and returns an R type.
In lambda expression, it is expressed as T -> R.
Like a function in a mathematical expression, it takes a specific value and returns a different value.
T and R can also use the same type.
2.5. Comparator
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
Comparator takes two T type arguments and returns a int type.
In lambda expression, it is expressed as (T, T) -> int.
2.6. Runnable
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Runnable does not receive any object and does not return.
In a lambda expression, it is expressed as () -> void.
Runnable As the name suggests, it means โexecutable,โ and you can think of it as only executing as the name suggests.
2.7. Callable
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
Callable takes no arguments and returns a type T object.
In lambda expression, it is expressed as () -> T.
Similar to Runnable, Callable makes more sense when you think of it as โcallable.โ
Supplier vs Callable
Supplier and Callable are exactly the same.
Returns a specific type without receiving any arguments.
What is the difference between the two?
In fact, you can just think that there is no difference.
Only Callable is a concept that appeared for parallel processing along with Runnable, and functions such as ExecutorService.submit receive Callable as an argument.
3. Bi interface that takes two arguments
For Predicate, Consumer, and Function that receive specific arguments, there is an interface that can receive more than one type.
| functional interface | Descriptor | Method |
| BiPredicate |
(T, U) -> boolean
|
boolean test(T t, U u)
|
| BiConsumer |
(T, U) -> void
|
void accept(T t, U u)
|
| BiFunction |
(T, U) -> R
|
R apply(T t, U u)
|
4. Basic specialized interface
The functional interface we have seen so far is called generic functional interface.
All types in Java are reference types or primitive types.
- Reference Type: Byte, Integer, Object, List
- Primitive Type: int, double, byte, char
In Consumer , T can only be used as a reference type.
Java provides boxing and unboxing functions to convert basic types and reference types.
- Boxing: Basic type -> Reference type (
int -> Integer) - Unboxing: Reference type -> basic type (
Integer -> int)
In addition, it provides a function called Autoboxing that automatically converts so that developers can develop without worrying about boxing and unboxing.
For example, in List, you can use basic types like list.add(3) thanks to autoboxing.
However, because this conversion process costs money, functional interfaces provide a basic-type specialized functional interface to avoid this autoboxing behavior.
If you are sure that only certain types will be accepted, such as IntPredicate, LongPredicate, etc., it is better to use basic specialized interfaces.
In addition to the interfaces introduced below, basic type specialization is also provided for the UnaryOperator and Bi interfaces.
4.1 Predicate (T -> boolean)
After receiving the basic type, return boolean
IntPredicateLongPredicateDoublePredicate
4.2. Consumer (T -> void)
Consume after receiving the basic type
IntConsumerLongConsumerDoubleConsumer
4.3. Function (T -> R)
Receives a basic type and returns a basic type
IntToDoubleFunctionIntToLongFunctionLongToDoubleFunctionLongToIntFunctionDoubleToIntFunctionDoubleToLongFunction
Receives basic type and returns R type
IntFunctionLongFunctionDoubleFunction
Receives type T and returns basic type
ToIntFunctionToDoubleFunctionToLongFunction
4.4. Supplier (() -> T)
Return basic type without receiving anything
BooleanSupplierIntSupplierLongSupplierDoubleSupplier
References




Leave a Reply