Introduction to Java Functional SAM Interface
Interfaces having exact one abstract method are known as functional interfaces. Also known as Single Abstract Method Interfaces (SAM Interface).
Single abstract method interface means, this interface must have one abstract method. However there can be any number of default methods.
First of all this is not new concept of Java 8 however, new annotation @FunctionalInterface is added in java 8 features.
Adding @FunctionalInterface annotation enforces that the interface has exact one abstract method. While adding @FunctionalInterface annotation is not mandatory.
Functional interface annotation enforces the rule of single responsibility. [more about Single responsibility principle]
Usage and Syntax of Java 8 Functional SAM Interface
We can use functional interface like any other interface in java.
However from java 8 functional interfaces are very important, because we use functional interface for implementing Lambda expressions. You can read more about lambda expression here.
For writing lambda expression we mostly use functional interface. Due to many functional interfaces newly added in java 8, we don’t have to write a new functional interface while writing lambda expressions.
Java.util.function Package contains newly added functional interfaces which are commonly used.
Following are the valid java functional(SAM) interface examples:
public interface MyFunctionalInterface {
public void abstractMethod();
}
public interface MyFunctionalInterface {
public void abstractMethod();
}
As the rule suggests, functional interface must have exact one abstract method.
In contrast we can add as many default methods as per our requirements, because default methods are not abstract. This is the reason why some java classes are called as functional interfaces even if it has many methods.
For example, Java Comparator class is a functional interface even though it has 7 default methods.
public interface MyFunctionalInterface {
public void abstractMethod();
// Allowed to add default methods
default void print(){
System.out.println(“Default Method 1“);
}
default void print2(){
System.out.println(“Default Method 2“);
}
}
...
@FunctionalInterface
public interface Comparator {
int compare(T var1, T var2);
// Allowed to add default methods
default Comparator reversed() {
return Collections.reverseOrder(this);
}
...
}
Overriding java.lang.Object class method as abstract
Overriding and making a method from java.lang.Object class as abstract in our sam functional interface , also does not count toward the interface’s abstract method. Because any implementing class will always have implementation inherited from java.lang.Object or elsewhere.
public interface MyFunctionalInterface {
void abstractMethod();
boolean equals(Object obj); //Because not considered as functional interface abstract method
public String toString(); //Because not considered as functional interface abstract method
}
For example Java Comparator is a functional interface But, it overrides equals() as abstract method
...
@FunctionalInterface
public interface Comparator {
int compare(T var1, T var2);
boolean equals(Object var1);
....
}
Java.util.function Package
As discussed many functional interfaces are added in java 8 java.util.function package. Let's understand more about function package of java 8. These new classes are also known as SAM interfaces.
The SAM interfaces in Java.util.function package are manly categorized into 4 types
- Consumer: These interfaces have a method which takes input, but does not return anything
Syntax: Consumer<InputType> object = variable -> method body;
Example: Consumer<String> print = str -> System.out.println(str); - Supplier : In contrast, these interfaces have a method which returns something without taking any input
Syntax: Supplier<ReturnType> object = ()-> method body;
Example: Supplier<Long> useIdSupplier = ()-> userDao.getMaxId()+1; - Predicates : These interfaces have a method which takes input and returns boolean value
Syntax: Predicate<InputType> object = variable -> method body;
Example: Predicate<Long> evenChecker = n->n%2==0; - Function : These interfaces have a method which takes input and returns output
Syntax: Function<InputType,ReturnType> object = variable -> method body;
Example: Function<Long, Long> square = n -> n*n;
Each of the above 4 categories has provided variety of special interfaces for most common primitive data types.
We can use Consumer, Supplier, Predicate or Function interfaces with wrapper classes, however using a specific interface makes code more cleaner and easy. Let's see the different variants:
All of the 4 categories provide special interfaces for int, long and double, However Supplier provides an extra interface for boolean
- IntConsumer, LongConsumer , DoubleConsumer
- IntSupplier, LongSupplier, DoubleSupplier, BooleanSupplier
- IntPredicate, LongPredicate, DoublePredicate
- IntFunction<R>, LongFunction<R>, DoubleFunction<R>
Function provides even more special functions for converting values int, long and double. Name of the classes are self-explanatory
- ToIntFunction, ToLongFunction, ToDoubleFunction
- IntToLongFunction, LongToIntFunction
- IntToDoubleFunction, DoubleToIntFunction
- LongToDoubleFunction, DoubleToLongFunction
Consumer, Predicate and Function have variants that accept 2 input arguments. Supplier doesn't accept any arguments so it does not have any class of this type
- BiConsumer<T,U> Accepts two input arguments of type T and U , returns nothing.
- BiPredicate<T,U> Accepts two input arguments of type T and U , returns boolean value.
- BiFunction<T,U,R> Accepts two input arguments of type T and U , returns a result of type R.
BiConsumer has 3 even more variants which accept one object and other primitive (int long or double)
- ObjIntConsumer Accepts object of t type and int
- ObjLongConsumer Accepts object of t type and Long
- ObjDoubleConsumer Accepts object of t type and Double
BiFunction has 3 more variants for accepting 2 arguments and convert to primitive (int long or double)
- ToIntBiFunction<T,U> Accepts two input arguments of type T and U , returns int result.
- ToLongBiFunction<T,U> Accepts two input arguments of type T and U , returns Long result.
- ToDoubleBiFunction<T,U> Accepts two input arguments of type T and U , returns Double.
In addition Function provides more types that accept and return object of same type
- UnaryOperator Accepts single operand that returns a result of same type.
- IntUnaryOperator Accepts a int value and returns int result.
- LongUnaryOperator Accepts a Long value and returns int result.
- DoubleUnaryOperator Accepts a Double value and returns int result.
- BinaryOperator Accepts two parameter of same type and returns result of same type.
- IntBinaryOperator Accepts two int value and returns int result.
- LongBinaryOperator Accepts two Long value and returns Long result
- DoubleBinaryOperator Accepts two Double value and returns Double result
Fast track reading :
- Also known as Single Abstract Method interfaces (SAM Interface)
- Exactly one abstract method is allowed
- @FunctionalInterface is optional and it is valid even if annotation would be omitted.
- Default methods are not abstract so we can add any number of default methods to the functional interface
- Allows overriding Object class methods as abstract
- Functional interfaces are very important for writing lambda expression
- Many functional interfaces are added in java 8 java.util.function package
Type | Consumer | Supplier | Predicate | Function |
Summary | Accepts something | Produces something | Process and return true/false | Accepts something and produces something |
Input | Parameter | No Input | Parameter | Parameter |
Returns | - | Result | Always boolean | Result |
primitive variants | IntConsumer LongConsumer DoubleCnsumer | IntSupplier LongSupplier DoubleSupplier BooleanSupplier | IntPredicate LongPredicate DoublePredicate | IntFunction<R> LongFunction<R> DoubleFunction<R> |
For conversion | - | - | - | ToIntFunction<T> ToLongFunction<T> ToDoubleFunction<T> IntToLongFunction IntToDoubleFunction LongToDoubleFunction |
For 2 inputs | BiConsumer<T,U> | - | BiPredicate<T,U> | BiFunction<T,U,R> |
2 input variants | ObjIntConsumer<T> ObjLongConsumer<T> ObjDoubleConsumer<T> | - | - | ToIntBiFunction<T,U> ToLongBiFunction<T,U> ToDoubleBiFunction<T,U> |
Accept and return same type | - | - | - | UnaryOperator IntUnaryOperator LongUnaryOperator DoubleUnaryOperator BinaryOperator |
Very good explanation of SAM. Thanks.
Thank you very much for your appreciation and reading the blog. you may also like my other posts related to java 8 lambda expression and Java option class in details.
Very well explained. Read so many articles but now I understood. Thanks for explaining in detail.
Hello Sobia,
Thank you very much for taking time to read and appreciate the efforts. This motivates us to keep up our work!! Stay tuned for more such interesting blogs. Hope you like them as well!!