This document provides a brief overview of Java 8 features including functional interfaces, lambda expressions, stream API, and Optional class. It discusses how functional interfaces provide target types for lambda expressions and can have a single abstract method. Lambda expressions allow implementing functional interfaces concisely without anonymous classes. The stream API provides a powerful way to process collections in a declarative way using lambda expressions. The Optional class avoids null pointer exceptions and allows chaining of method calls on objects that may be null.
5. 5
Default methods in an Interface
• Backward compatibility to interface APIs
• Less number of classes /interfaces
• Prevents reimplementation of complete APIs
• API developer can provide reference implementation of methods
interface BankingAPI{
BigDecimal calculateMaturityAmount(BigDecimal inAmount);
default BigDecimal calculateTDSOnAmount(BigDecimal inAmount){
return inAmount.multiply(new BigDecimal(0.1));
}
}
7. 7
Functional Interfaces
Functional interfaces provide target types for lambda expressions and method
references.
1. It has a single abstract method called the functional method
2. The lambda expression parameter and return type are matched for the
functional interface.
3. Can have any number of default methods.
4. Functional interfaces are annotated with @FunctionalInterface
@FunctionalInterface
public interface Iterable<T> {
Iterator<T> iterator();
}
8. 8
Lambda Expressions
• A Lambda expression is written as
• Where argument type can be inferred by the compiler
• Has access to the class variables using this
• Target type of Lambda is FunctionalInterface
TypeName objName = (argument..)->{Body};
9. 9
Examples of Lambda Expressions
MathOperation o = (a,b) ->{return a*b;};
o.operation(4,5);
BiFunction<Integer, Integer, Integer> o1 = (a,b) ->{return a+b;};
BiFunction<Integer, Integer, Integer> o1 =(a,b) -> a+b;
int sum = o1.apply(4, 5);
MathOperation o = (a,b) ->{return a*b+effectiveFinalInt+1; };
10. 10
Lets Lambdify …
Runnable runnable = new Runnable() {
public void run() {
System.out.println("Hello you are in
Runnable");
}
};
Runnable runnable = () ->{
System.out.println("I am in Lambda
land");
};
This creates a
<ClassName>$<Number>.class file for
the above anonymous class
Lets see how Lambda works internally
11. 11
Decompiling the λ expression
• Run the class with following structure
• The Java runtime creates a .class file whose decompiled code looks like
• The class file structure of LambdaTest.class gives the following information
java --Djdk.internal.lambda.dumpProxyClasses=<FolderPath> <ClassNames or JarName>
final class LambdaTest$$Lambda$1 implements Runnable {
private LambdaTest$$Lambda$1() {
}
public void run() {
LambdaTest.lambda$0();
}
}
??
12. 12
Lambda some more information
● invokedynamic (Java 7) is used to for Lambda expression implementation
● Implementation details can be JVM specific and are deferred until runtime
● Compiler encounters lambda expression, lambda is 'desugared' into a private
static method with appropriate signature, Compiler indicates bootstrap method
and provides static arguments about lambda
● Compiler generates invokedynamic instruction referencing bootstrap method
14. 14
Stream API
• Provides a wrapper around a Collection that carries values from a source.
• It provides a fluent interface to create a pipeline or chain of the operations.
• Powerful, faster and more memory efficient and are designed for lambdas
• Employs lazy evaluation and are implicitly parallelizable to multiple cores.
• Inbuilt SQL like aggregation functions like sum, sort, max, min, average
15. 15
List<Employee> list = employeeList.stream().parallelStream().map(e -> {e.setSalary(.map(R F.apply(T t))
Examples of Stream API
e.getSalary() * 1.2); return e;}).
Can add any operation on stream like map,
reduce or can collect the employees
collect(Collectors.toList());
List<String> teamList = new ArrayList<>();
/* Add List Members
*
*/
Stream<String> teamStream = teamList.stream() ;
Stream<String> teamStream = Stream.of("Allahbaksh","Avitash","Vivek");
Set<String> teamSet = teamStream.collect(Collectors.toSet());
Some more examples
17. 17
Wise Man Says..
One of my billion $ mistake was to creation
of Null reference, I created it because it
was so tempting and easy to implement
18. 18
Tired of checking NullPointerException?
• String location = employee.getManager().getUnit().getLocation();
• What if Manager is not present and getManager() returns null.
• Lack of Documentation or lack of Reading a documentation.
• To remove such errors we use nested checks like
if(employee.getManager()!=null){
if(employee.getManager().getUnit()!=null){
if(employee.getManager().getUnit().getLocation()!=null){
// Business Logic
}
}
}
19. 19
Example of Optional
public class Unit{
public Optional<String> location;
public Optional<String> getLocation(){
return location;
}
}
public class Employee{
public Optional<Manager> manager;
public Optional<Manager> getMananger(){
return manager;
}
}
String location =
employee.flatMap(Employee::getManager).flatMap(Manager::getUnit)
.map(Unit::getLocation);
public class Manager extends Employee{
public Optional<Unit> unit;
public Optional<Unit> getUnit(){
return unit;
}
}
20. 20
Some methods of Optional class
• boolean isPresent()
• T get()
• void ifPresent(Consumer<? super T> consumer)
• Optional.of(T value)