Introduction to Java Functional(SAM) Interface
Interfaces having exact one abstract method is known as functional interface. Also known as Single Abstract Method Interfaces (SAM Interfaces). One abstract method means default methods or abstract method whose implementation is available by default are allowed. We will study both the cases with java.util.function package which is newly added.
First of all this is not new concept of Java 8 however, new annotation @FunctionalInterface is added in java 8.
Adding @FunctionalInterface annotation enforces that the interface has exact one abstract method. While adding @FunctionalInterface annotation is not mandatory. If the interface has one abstract method this will be considered as Functional interface in Java 8.
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 write functional interface for general purpose to implement the interface.
However from java 8 functional interfaces are very important, because we use functional interface for implementing Lambada expressions. Lambda is nothing but the shorter way of anonymous implementation of function interface. If you are new, you can read more about lambda expression.
For writing lambda expression we need function interface. Thanks to java developers, we don’t have to write a new functional interface while writing lambda expressions. Due to many functional interfaces newly added in java 8. These are very commonly used in lambda expressions or method reference.
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 whey some java classes are called as functional interface even if it has many methods.
For example, Java Comparator class is a functional interface having 7 default methods even though it is valid functional interface.
public interface MyFunctionalInterface {
public void abstractMethod();
default void print(){ // because it is default method
System.out.println(“Default Method 1“);
}
default void print2(){ //because it is default method
System.out.println(“Default Method 2“);
}
}
…
@FunctionalInterface
public interface Comparator {
int compare(T var1, T var2);
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. Lets understand more about function package of java 8. This new classes are also known as SAM interfaces.
The sam interfaces in Java.util.function package are manly categorized into 4 types
- Consumer: This interface are having method which takes input, but does not return anything
Example Consumer<String> print = str -> System.out.println(str); - Supplier : In contrast this interface are having method which returns something without taking any input
Supplier<Long> useIdSupplier = ()-> userDao.getMaxId()+1; - Predicates : This interface are having method which takes input and returns boolean value
Predicate<Long> evenChecker = n->n%2==0; - Function : This interface are having method which takes input and returns output
Function<Long,Long> square = n -> n*n;
Each of the above all 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 class, 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 Interfaces)
- Exaclty 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.