Functions are re-useable pieces of code . Let us take an example from mathematics : f(x)=x2 +2 . When we assign a value to x , say, 1 we substitute x with 1 and return the result as 3. In the same way , we basically apply the same concept in programming. Similarly , Java 8 has a functional interface called Function.
Function<T,R> function =(T)->{ return R }
T – Type of input
R – Return type
Let us try to write a function to calculate the factorial of a number and return its value .
int factorial(int number ){
int fact=1;
for (int j = 1; j <= number; j++) {
fact = fact * j;
}
return fact;
}
We cannot use this normal function without tying with a class. We have to either use it in our object , or access the function by means of inheritance. Let us re-write it into a lambda function.
Function<Integer, Integer> factorial = i -> {
int fact = 1;
int number = i;
for (int j = 1; j <= number; j++) {
fact = fact * j;
}
return fact;
};
The above code snippet does the same function as the one which we have written in conventional way, except it has been assigned to a functional interface called Function. Since it is a lambda expression you can pass it as a variable, define it in one place and use it every where. In addition to the execution of the function , there are some powerful features that we can leverage .
Apply
This is the single abstract method for which we write the lambda expression . As illustrated in the example above , we can execute the function by calling the method apply .
int result = factorial.apply(5)
This is equal to calling factorial function like this :
int result = factorial(5);
Compose
default <V> Function<V,R> compose(Function<? super V,? extends T> before)
Compose gives us an ability to execute a function before calling the actual function . This is really handy when you want to validate / do some kind of pre-processing of inputs. If we were to do the same in the imperative way , the caller has either to incorporate the pre-processing logic or to pass on the responsibility to actual function. In imperative way, we are breaking the Single Responsibility Principle.
We will use the factorial example with a small change. Our requirement is to double the value of input variable.
private static void factorialCompose() {
Function<Integer, Integer> factorial = i -> {
int fact = 1;
int number = i;
for (int j = 1; j <= number; j++) {
fact = fact * j;
}
return fact;
};
Function<Integer,Integer> multiplyTwice= i->i*2;
factorial.compose(multiplyTwice)
.apply(5);
System.out.println("Factorial of 5 " + factorial.compose(multiplyTwice)
.apply(5));
}
We can see that we haven’t made any change to the factorial method, but simply plugged in multiplyTwice function using compose.
andThen
This another handy method which will help us to call another function after executing our function.
default <V> Function<T,V> andThen(Function<? super R,? extends V> after)
This enables us to execute some clean up/logging code after our function is executed. Similar to compose we can plug-in other functions to get the desired result .
private static void factorialCompose() {
Function<Integer, Integer> factorial = i -> {
int fact = 1;
int number = i;
for (int j = 1; j <= number; j++) {
fact = fact * j;
}
return fact;
};
Function<Integer,Integer> multiplyTwice= i->i*2;
factorial.compose(multiplyTwice)
.apply(5);
System.out.println("Factorial of 5 " + factorial.compose(multiplyTwice)
.apply(5));
}
Other variations
| BiFunction<T,U,R> | Represents a function that accepts two arguments and produces a result. |
| DoubleFunction<R> | Represents a function that accepts a double-valued argument and produces a result. |
| DoubleToIntFunction | Represents a function that accepts a double-valued argument and produces an int-valued result. |
| DoubleToLongFunction | Represents a function that accepts a double-valued argument and produces a long-valued result. |
| Function<T,R> | Represents a function that accepts one argument and produces a result. |
| IntFunction<R> | Represents a function that accepts an int-valued argument and produces a result. |
| IntToDoubleFunction | Represents a function that accepts an int-valued argument and produces a double-valued result. |
| IntToLongFunction | Represents a function that accepts an int-valued argument and produces a long-valued result. |
| LongFunction<R> | Represents a function that accepts a long-valued argument and produces a result. |
| LongToDoubleFunction | Represents a function that accepts a long-valued argument and produces a double-valued result. |
| LongToIntFunction | Represents a function that accepts a long-valued argument and produces an int-valued result. |
| ToDoubleBiFunction<T,U> | Represents a function that accepts two arguments and produces a double-valued result. |
| ToDoubleFunction<T> | Represents a function that produces a double-valued result. |
| ToIntBiFunction<T,U> | Represents a function that accepts two arguments and produces an int-valued result. |
| ToIntFunction<T> | Represents a function that produces an int-valued result. |
| ToLongBiFunction<T,U> | Represents a function that accepts two arguments and produces a long-valued result. |
| ToLongFunction<T> | Represents a function that produces a long-valued result. |
You can get more details from the official documentation



