Java 8 SAM Functional interface :java.util.function package

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:

@FunctionalInterface
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.

@FunctionalInterface
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“);

}

}

package java.util;

@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.

@FunctionalInterface                             // valid java 8 SAM interface example
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

package java.util;                           //VALID

@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

  1. 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);
  2. 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;
  3. 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;
  4. 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
TypeConsumerSupplierPredicateFunction
SummaryAccepts somethingProduces somethingProcess and return true/falseAccepts something and produces something
InputParameter  No InputParameterParameter
Returns  –ResultAlways booleanResult
primitive variantsIntConsumer
LongConsumer
DoubleCnsumer
IntSupplier
LongSupplier
DoubleSupplier
BooleanSupplier
IntPredicate
LongPredicate
DoublePredicate
IntFunction<R>
LongFunction<R>
DoubleFunction<R>
For conversion  –  –  –ToIntFunction<T>
ToLongFunction<T>
ToDoubleFunction<T>


IntToLongFunction
LongToIntFunction


IntToDoubleFunction
DoubleToIntFunction


LongToDoubleFunction
DoubleToLongFunction

For 2 inputsBiConsumer<T,U>  –BiPredicate<T,U>BiFunction<T,U,R>
2 input variantsObjIntConsumer<T>
ObjLongConsumer<T>
ObjDoubleConsumer<T>
  –  –ToIntBiFunction<T,U>
ToLongBiFunction<T,U>
ToDoubleBiFunction<T,U>
Accept and return same type  –  –  –UnaryOperator
IntUnaryOperator
LongUnaryOperator
DoubleUnaryOperator


BinaryOperator
IntBinaryOperator
LongBinaryOperator
DoubleBinaryOperator

2 comments

Leave a Reply

Your email address will not be published. Required fields are marked *