Java 8 Bootcamp
What are Lambdas ?
Functional Interface
Functional Interface vs Anonymous inner class
Method Reference
Constructor Reference
Functional Interfaces provided by java.util.functions.*
Default Methods and Multiple Inheritance
Overview of Streams
Core Stream methods
Optional class
Lazy evaluation
Agenda
- Higher order functions
- Immutibility
- Pure Function
Pillars of functional programming
Imperative style of programming
Vs
Declarative style of programming
Anonymous functions
Can be assigned to a variable
Can be passed to functions
Can be returned from functions
What are lambdas?
Running the code in the separate thread.
Running the code multiple times.
Running the code at the right point in the algorithm.
Running the code when something happens.
Running the code when only necessary.
Deferred Execution
How to implement interface containing one abstract method?
public interface MyInterface {
void display();
}
Old way
Create a class and implment the interface
Anonymous inner class
New way
lambdas
MyInterface myInterface=new MyInterface() {
@Override
public void display() {
System.out.println("This is anonymous inner class");
}
};
myInterface.display();
MyInterface myInterface=()-> {
System.out.println("This is anonymous inner class");
};
myInterface.display();
Functional Interface
Interface containing only one abstract method is known as Functional Interface.
public interface MyInterface {
int operation(int a,int b);
}
MyInterface mylambda =(a,b)-> a+b;
System.out.println(mylambda.operation(2,3));
Goodies with lambdas
- Type inferencing
- Implied return value
- Omitting parentheses
JDK Functional Interfaces
Runnable
Runnable runnable=()->System.out.print("Running in another thread");
new Thread(runnable).start();
Comparator
Employee e1=new Employee("Pulkit",40000,23);
Employee e2=new Employee("Jitu",20000,24);
List<Employee> list= Arrays.asList(e1, e2);
Collections.sort(list,(emp1,emp2)->{
return emp1.getAge()-emp2.getAge();
});
Exercise 1
Write the following a functional interface and implement it using lambda:
(1) First number is greater than second number or not
Parameter (int ,int ) Return boolean
(2) Increment the number by 1 and return incremented value
Parameter (int) Return int
(3) Concatination of 2 string
Parameter (String , String ) Return (String)
(4) Convert a string to uppercase and return
Parameter (String) Return (String)
Method References
It is not always necessary to use a lambda for the implementation of functional interface. Static and instance methods can also be used for thispurpose.
public interface MethodReferenceInterface {
void display();
}
public class Dummy {
static void staticMethod(){
System.out.println("Static method");
}
void instanceMethod(){
System.out.println("Instance Method");
}
public static void main(String[] args) {
MethodReferenceInterface staticMethod=Dummy::staticMethod;
staticMethod.display();
MethodReferenceInterface instanceMethod=new Dummy()::instanceMethod;
instanceMethod.display();
}
}
Constructor Reference
Constructer reference is just like method reference except that the name of the method is new.
public interface DemoInterface {
String myMethod(char [] chars);
}
DemoInterface demoInterface = String::new;
String str=demoInterface.myMethod(new char[]{'a', 'b', 'c', 'd'});
System.out.println(str);
Exercise 2
-
Create a functional interface whose method takes 2 integers and return one integer.
-
Using (instance) Method reference create and apply add and subtract method and using (Static) Method reference create and apply multiplication method for the functional interface created.
- Create an Employee Class with instance variables (String) name, (Integer)age, (String)city and get the instance of the Class using constructor reference
Variable Capture
-
Lambdas can interact with variables defined outside the body of the lambda.
-
Using variable outside the body of a lambda expression is called variable capture.
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
int var=10;
integerList.forEach(e->System.out.println(e+var));
Effectively Final Local Variables
Lambdas can refer to local variables that are not declared final (but are never modified)
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
int var=10;
var++;
// This line will generate error
// because we are changing a variable before using it inside lambda expression
integerList.forEach(e->System.out.println(var));
this inside Anonymous Inner class
interface Demo{
void display();
}
public class ThisDemo {
Integer myInteger=1;
public void myMethod(){
Demo demo=new Demo() {
Integer myInteger=2;
@Override
public void display() {
System.out.println(this.myInteger);
}
};
demo.display();
}
public static void main(String[] args) {
new ThisDemo().myMethod();
}
}
this inside lambda
interface Demo{
void display();
}
public class ThisDemo {
Integer myInteger=1;
public void myMethod(){
Demo demo=()-> {
Integer myInteger=2;
System.out.println(this.myInteger);
};
demo.display();
}
public static void main(String[] args) {
new ThisDemo().myMethod();
}
}
Lambda vs Anonymous Inner Class
-
Inner class can have multiple methods whereas lambdas can have only one method.
-
this points to the anonymous inner class object in case of anonymous inner class but in case of lambdas it points to enclosing object.
Java.util.function
Java.util.function has many reusable intefaces
(1) Simple typed interfaces
DoublePredicate, IntConsumer, LongUnaryOperator
(2) Generically typed intefaces
Consumer, Supplier, Predicate, Function
Exercise 3
Implement following functional interfaces from java.util.function using lambdas:
-
(1) Consumer
-
(2) Supplier
-
(3) Predicate
-
(4) Function
How Interface is different in Java 8 from Java 7
Java 7 and earlier | Java 8 |
---|---|
Can only have abstract methods | Can have concrete methods and abstract methods |
Cannot have static methods | Can have static methods |
Default methods in interface
If you want define a method inside an interface you can do it by making the method default.
interface inter1 {
default void display(){
System.out.println("inter1");
}
}
public class DefaultMethods implements inter1 {
public static void main(String[] args) {
DefaultMethods defaultMethods=new DefaultMethods();
defaultMethods.display();
}
}
Static methods in interface
You can also define static method inside interface
interface inter1 {
static void display(){
System.out.println("inter1");
}
}
public class DefaultMethods {
public static void main(String[] args) {
inter1.display();
}
}
Overriding default method
interface inter1 {
default void display(){
System.out.println("inter1");
}
}
public class DefaultMethods implements inter1 {
public void display(){
System.out.println("DefaultMethods");
}
public static void main(String[] args) {
DefaultMethods defaultMethods=new DefaultMethods();
defaultMethods.display();
}
}
Multiple inheritance and default methods
interface inter1 {
default void display(){
System.out.println("inter1");
}
}
interface child1 extends inter1{
default void display(){
System.out.println("child1");
}
}
interface child2 extends inter1{
default void display(){
System.out.println("child2");
}
}
public class DefaultMethods implements child1,child2 {
public void display(){
System.out.println("DefaultMethods");
}
public static void main(String[] args) {
DefaultMethods defaultMethods=new DefaultMethods();
defaultMethods.display();
}
}
Exercise 4
(1) Create and access default and static method of an interface.
(2) Override the default method of the interface.
(3) Implement multiple inheritance with default method inside interface.
Streams
-
Wrappers around data source.
-
Support many convinient and high-performance operations expressed with lambdas.
-
Streams do not store data.
-
Lazy evaluation.
- Streams do not mutate their source.
3 stages of stream pipeline operations
-
Create stream.
-
Specify intermediate operations for transforming the initial stream.
- Specify terminal operation to produce the result.
3 common ways of creating a stream
-
someList.stream()
-
Stream.of(arrayOfObjects) not primitives
- Stream.of(val1,val2,....)
Method types
Intermediate Methods
- These are methods that produce other Streams. These methods don’t get processed until there is some terminal method called.
- map (and related mapToInt, flatMap, etc.), filter, distinct,sorted, peek, limit, skip, parallel
Terminal Methods
- These methods terminates the stream.
- forEach, toArray, reduce, collect, min,max, count, anyMatch, allMatch, noneMatch, findFirst,findAny
-Short-circuit methods
- These methods cause the earlier intermediate methods to be processed only until the short-circuit method can be evaluated.
- anyMatch, allMatch, noneMatch, findFirst, findAny, limit, skip
Core stream methods
forEach(Consumer)
Calling a lambda on each element of stream
List<Integer> list= Arrays.asList(1,2,3,4,5,6);
list.forEach(System.out::println);
map(Function)
Transforming stream by passing each element through a Function
Produces a new Stream that is result of applying a Function to each element of origin Stream
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
list.stream()
.map(e -> e * 2)
.forEach(System.out::println);
filter(Predicate)
Keep only the element that pass the predicate
list.stream()
.filter(e -> e > 2)
.forEach(System.out::println);
mapToInt
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
System.out.println(
list.stream()
.mapToInt(e -> e).max()
);
Collect
toList()
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
System.out.println(
list.stream()
.filter(e -> e > 3)
.collect(Collectors.toList())
);
toSet()
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 5, 6, 7);
System.out.println(
list.stream()
.filter(e -> e > 3)
.collect(Collectors.toSet())
);
joining()
List<String> list = Arrays.asList("abc","def");
System.out.println(
list.stream()
.collect(Collectors.joining(","))
);
summingIn()
List<Integer> list = Arrays.asList(1, 2, 3, 4);
System.out.println(
list.stream()
.collect(Collectors.summarizingInt(x -> x * 2))
);
averagingInt()
List<Integer> list = Arrays.asList(1, 2, 3, 4);
System.out.println(
list.stream()
.collect(Collectors.averagingInt(x -> x * 2))
);
counting()
List<Integer> list = Arrays.asList(1, 2, 3, 4);
System.out.println(
list.stream()
.collect(Collectors.counting())
);
toMap()
List<Integer> list = Arrays.asList(1, 2, 3, 4);
System.out.println(
list.stream()
.collect(Collectors.toMap(e -> e, e -> e + " Number" ))
);
-
Optional either stores a T or stores nothing. Useful for methods that may or may not find a value. New in Java 8.
-
- The value of findFirst of Stream is an Optional
-
- Some common operations on optional stream
-
value.get()
-
value.orElse(other)
-
value.orElseGet(Supplier)
- value.isPresent()
Optional
Parallel Stream
By designating that a Stream be parallel, the operations are automatically done in parallel
Designating streams as parallel
- anyStream.parallel()
- anyList.parallelStream()
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
list.stream().parallel().forEach(System.out::println);
Exercise 5
-
Collect all the even numbers from an integer list.
-
Sum all the numbers greater than 5 in the integer list.
-
Find average of the number inside integer list after doubling it.
- Find the first even number in the integer list which is greater than 3.
Java 8 Bootcamp
By Pulkit Pushkarna
Java 8 Bootcamp
- 1,558