Java 8 Lambda Expression
Java 8 Lambda Expression
Lets say we have an interface which has exactly one abstract method (i.e, functional
interface) then only we can use the lambda expressions.
Lets try to understand the essence of why should we use the lambda expressions
using an example.
Using the above approaches were follows before Java 8 but there are some dis
advantages with this as follows
with approach 1 we are always required to create a separate class to define the
method of functional interface what if the application has 100 of functional
interfaces then we have to create 100 classes just to provide the definition and
access which becomes cumbersome.
with approach 2 though we are able to achieve in the same file the code looks
clumsy and what if there are many abstract methods(not a functional interface)
and we just want to use 1 method at a specific place then also we have to provide
the implementation os unused methods which is waste of time, and also harder to
read.
(parameters) → {
// business logic
If the function is accepting only one parameter then we can remove () for the
parameters and reduce as follows
parameter → {
If the function has only one statement as the business logic we can even remove
the enclosing {} as follows
If the function has only one statement and we wanted to return something we can
further get rid of the return keyword as follows
If there are no parameters then the () for the parameter is mandatory as follows
() → business logic
Lets say we have a method which accepts 2 integers and return the sum of those 2
values
(To use lambda the thumb rule is we have to have a functional interface ) so lets say
we have a functional interface as follows
And to use this sum method we can define the lambda expression as follows
Always the lambda expression is assigned to the Reference of the functional interface
and using that reference variable the abstract method is called in the case of having
our own custom functional interfaces.
For our convenience Java came up with the built in Functional Interfaces using which
we can easily write the business logic in the functional programming approach all of
them belongs to java.lang.function package
1) Java.lang.function.Predicate<T>
Usage - This can be used when ever we want to write the business logic which accepts
single parameter(of any type primitive or non primitive) and the function returns
boolean value.
Example - we want to see if the given number is even or not (if even return true or
false)
boolean test(T t) → As we saw this is the method which we use to invoke the
lambda expression
and(Predicate<T> other) → If there are more than one conditions to check we can
combine all the lambda expressions using the and default method which will
return the composite predicate (think this is same like logical and and evaluates
left to right and so said to be short circuiting as if first is false second does not
even execute)
or(Predicate<T> other) → same as the and but this works same as the logical or
operator (returns the short circuiting logical or composite predicate same as and)
negate() → returns the Predicate that represents the logical negation of the called
predicate (i.e true becomes false and vice versa)
isEqual(Object target) → this returns the Predicate which is object →
object.isEquals(target) so we can run the the test(T t) which executes this logic
with the input provided.
Usage - When in the business logic if the method accepts 1 input of any type and
returns a value of any type then use the Function.
T → Input type
R → Return type
Example - lets say we are providing the input integer to the method and expecting
the square of that value then
Traditional way Functional programming
Here in the Function<T,R> we have an abstract method apply(T t) which takes the
mentioned input(T) and return the mentioned type ® and also there are some other
methods as folllows
3) java.lang.Function.UnaryOperator<T>
Usage - When the business logic has the requirement of having the same type of
parameter and return type then use UnaryOperator.
All the methods discussed above work exactly same for this UnaryOperator also
4) java.lang.Function.Consumer<T>
Usage - When the function only takes the input but does not return anything then use
the Consumer
Example - Lets say we want to append some string to the already presented string
and print it without returning as below
Traditional Approach Functional Programming
Usage - When having a scenario where the function should not accept any input but
provides the output of given Type T.
Example - say we have business requirement of getting the OPT we no need to give
any input as follows.
This Supplier<T> (T here is the return type) has only one abstract method no
static and default methods here
All the Functional Interfaces discussed earlier are accepting the input of type Object
(That is not the primitive type). But we worked with the primitive types in all the
examples. so what exactly happened ?
The primitive type before sent as the parameter is Auto Boxed to its Wrapper class
and is passed.
In the lambda when ever we are performing the operations the Wrapper class is
converted to the primitive type to support the computations
At last the primitive type is again converted to the wrapper class while returning
the computational output.
This way if we have a list of many primitive types and we peform lanbda expression
using the above functional interfaces all these steps needs to be performed which will
degrade the performance significantly so Java came up with the Primitive
Functional Interfaces.
java.util.function.IntPredicate - will always accept the int type and return boolean
java.util.function.DoublePredicate - will always accept the double and return
boolean
java.util.function.LongPredicate - will always accept the long and return boolean
java.util.function.IntFunction<R> - will always accept the int type and return the
specified type (R)
java.util.function.DoubleFunction<R> - will always accept the double type and
return specified type (R)
java.util.function.LongFunction<R> - will always accept the long type and return
specified type (R)
java.util.function.ToIntFunction<T> - will accept type T but always return int type
java.util.function.ToDoubleFunction<T> - will accept type T but always return
double type
java.util.function.ToLongFunction<T> - will accept type T but always return long
type
java.util.function.IntToDouble - will accept int and return double
Note - There are still many interfaces of same kind with the BiFunctional also but its
easy to identify with the naming convention of the interface
5) For Unary Functional Interface (same input type and return value)