Java 1.
8v Features
Java 1.0
Java 1.1
Java 1.2 (Collection Framework)
..
Java 1.5 (Big Release)
..
Java 1.8 (Big Release) ------- Functional Programming
..
Java 19
Java 1.8v Features
-> Java 1.8v introduced lot of new features in java
-> Java 1.8v new features changed java programming style
Main Objectivies of Java 1.8v
-> Simplify Java Programming
-> Enable Functional Programming
-> Write more readable and concise code
Java 1.8 Features
1) Interface changes
1.1) Default Methods
1.2) Static Methods
2) Functional Interfaces (@FunctionalInterface)
2.1) Predicate & BiPredicate
2.2) Consumer & BiConsumer
2.3) Supplier
2.4) Function & BiFunction
3) Lambda Expressions
4) Method References & Constructor References
5) ****** Stream API ********
6) Optional class (to avoid null pointer exceptions)
7) Spliterator
8) StringJoiner
9) forEach ( ) method
10) Date & Time API
11) Nashron Engine
12) I/O Stream Changes (Files.lines(Path p))
13) Base64 Encoding & Decoding
Interface changes
-> Interface means collection of abstract methods
Note: The method which doesn't contain body is called as abstract method
-> A class can implement interface using "implements"
-> When a class is implementing interface its mandatory that class should implement
all abstract methods of that interface otherwise class can't be compile.
=> Here i am taking one interface with one abstract method. All the classes which are
implementing that interface should override interface method(s).
Example:-
interface Vehicle {
public abstract void startVechicle ( );
class Car implements Vehicle {
public void startVehicle ( ) {
// logic to start car
class Bus implements Vehicle {
public void startVehicle ( ) {
// logic to start bus
class Bike implements Vehicle {
public void startVehicle ( ) {
// logic to start bike
}
=> If we add new method in interface then Car, Bike and Bus will fail at compile time.
=> To overcome above problem we will use Default & Static methods
1) Interface can have concrete methods from 1.8v
2) Interface concrete method should be default or static
3) interface default methods we can override in impl classes
4) Interface static methods we can't override in impl classes
5) We can write multiple default & static methods in interface
6) Default & Static method introduced to provide backward compatibility
Ex: forEach ( ) method added in java.util.Iterable interface as default method in 1.8v
package in.azinit;
interface Vehicle {
public void start();
public default void clean() {
System.out.println("cleaning completed....");
}
public static void myClean() {
System.out.println("My cleaning completed....");
}
}
public class Car implements Vehicle {
@Override
public void start() {
System.out.println("car start...");
}
public static void main(String[] args) {
Car c = new Car();
c.start();
c.clean();
Vehicle.myClean();
}
}
Lambda Expressions
-> Introduced in java 1.8v
-> Java is called as Object Oriented Programming language. Everything will be
represented using Classes and Objects.
-> From 1.8v onwards Java is also called as Functional Programming Language.
-> In OOP language Classes & Objects are main entities. We need to write methods
inside the class only.
-> Functional Programming means everything will be represented in the form
functions. Functions can exist outside of the class. Functions can be stored into a
reference variable. A function can be passed as a parameter to other methods.
-> Lambda Expressions introduced in Java to enable Functional Programming.
What is Lambda
-> Lambda is an anonymous function
- No Name
- No Modifier
- No Return Type
Ex:-1
public void m1 ( ) {
s.o.p("hi");
( ) -> { s.o.p ("hi") }
Note: When we have single line in body then curly braces are optional
( ) -> s.o.p ("hi");
Ex:-2
public void add (int a, int b){
o s.o.p(a+b);
( int a, int b) -> { s.o.p (a+b) } ;
(or)
(int a, int b) -> s.o.p (a+b);
(or)
Lambda Expression : (a, b) -> s.o.p(a+b);
Ex:-3
public int getLength (String name) {
return name.length ( );
(String name) -> { return name.length ( ) };
(String name) -> return name.length ( ) ;
(name) -> return name.length ( );
Lambda Expression : name -> name.length ( ) ;
Ex:-4
public Double getEmpSalary (Employee emp) {
return emp.getSalary ( );
Lambda Expression : emp -> emp.getSalary ( );
Functional Interfaces
-> The interface which contains only one abstract method is called as Functional
Interface
-> Functional Interfaces are used to invoke Lambda expressions
-> Below are some predefined functional interfaces
Runnable ------------> run ( ) method
Callable ----------> call ( ) method
Comparable -------> compareTo ( )
-> To represent one interface as Functional Interface we will use
@FunctionalInterface annotation.
Example:-
@FunctionalInterface
public interface MyInterface {
public void m1( );
Note: When we write @FunctionalInterface then our compiler will check interface
contains only one abstract method or not.
-> In Java 8 several predefined Functional interfaces got introduced they are
1) Predicate & BiPredicate
2) Consumer & BiConsumer
3) Supplier
4) Function & BiFunction
-> The above interfaces are provided in java.util.function package
Predicate
-> It is predefined Functional interface
-> It is used check condition and returns true or false value
-> Predicate interface having only one abstract method that is test (T t)
interface Predicate{
boolean test(T t);
// Predicate Example
package in.azinit;
import java.util.function.Predicate;
public class PredicateDemo {
public static void main(String[] args) {
Predicate<Integer> p = i -> i > 10;
System.out.println(p.test(5));
System.out.println(p.test(15));
}
}
Task: Declare names in an array and print names which are starting with 'A' using
lambda expression.
String[ ] names = {"Anushka", "Anupama", "Deepika", "Kajol", "Sunny" };
package in.azinit;
import java.util.function.Predicate;
public class PredicateDemo2 {
public static void main(String[] args) {
String[] names = {"Anushka", "Anupama", "Deepika", "Kajol",
"Sunny"};
Predicate<String> p = name -> name.charAt(0) == 'A';
for(String name : names) {
if(p.test(name)) {
System.out.println(name);
}
}
}
Task-2: Take list of persons and print persons whose age is >= 18 using Lambda
Expression
package in.azinit;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
class Person {
String name;
int age;
Person(String name, int age){
this.name = name;
this.age = age;
}
public class PredicatePersonDemo {
public static void main(String[] args) {
Person p1 = new Person("John", 26);
Person p2 = new Person("Smith", 16);
Person p3 = new Person("Raja", 36);
Person p4 = new Person("Rani", 6);
List<Person> persons = Arrays.asList(p1, p2, p3, p4);
Predicate<Person> predicate = p -> p.age >= 18;
for(Person person : persons) {
if(predicate.test(person)) {
System.out.println(person.name);
}
}
}
Predicate Joining
-> To combine multiple predicates we will use Predicate Joining
and ( ) method
or ( ) method
Task-1: Print emp names who are working in Hyd location in DB team.
package in.azinit;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
class Employee {
String name;
String location;
String dept;
Employee(String name, String location, String dept){
this.name = name;
this.location = location;
this.dept = dept;
}
}
public class PredicateJoinDemo {
public static void main(String[] args) {
Employee e1 = new Employee("Raju", "Chennai", "DevOps");
Employee e2 = new Employee("Rani", "Pune", "Networking");
Employee e3 = new Employee("Ashok", "Hyd", "DB");
Employee e4 = new Employee("Ganesh", "Delhi", "Testing");
List<Employee> emps = Arrays.asList(e1, e2, e3, e4);
Predicate<Employee> p1 = (e) -> e.location.equals("Hyd");
Predicate<Employee> p2 = (e) -> e.dept.equals("DB");
Predicate<Employee> p3 = (e) -> e.name.startsWith("A");
//Predicate Joining
Predicate<Employee> p = p1.and(p2).and(p3);
for(Employee e: emps){
if(p.test(e)) {
System.out.println(e.name);
}
}
}
}
Supplier Functional Interface
-> Supplier is a predefined functional interface introduced in java 1.8v
-> It contains only one abstract method that is get ( ) method
-> Supplier interface will not take any input, it will only returns the value.
Ex: OTP Generation
package in.azinit;
import java.util.function.Supplier;
public class SupplierDemo {
public static void main(String[] args) {
Supplier<String> s = () -> {
String otp = "";
for(int i = 1; i <= 6; i++) {
otp = otp + (int) (Math.random() * 10);
}
return otp;
};
System.out.println(s.get());
System.out.println(s.get());
System.out.println(s.get());
System.out.println(s.get());
System.out.println(s.get());
}
}
Consumer Functional Interface
-> Consumer is predefined functional interface
-> It contains one abstract method i.e accept (T t)
-> Consumer will accept input but it won't return anything
Note: in java 8 forEach ( ) method got introduced. forEach(Consumer consumer)
method will take Consumer as parameter.
package in.azinit;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerDemo {
public static void main(String[] args) {
Consumer<String> c = (name) -> System.out.println(name+", good
Evening");
c.accept("Ashok");
c.accept("John");
c.accept("Rani");
List<Integer> numbers = Arrays.asList(10, 20, 30, 40);
// for Loop
//for each loop
//iterator
//list iterator
// list iterator
numbers.forEach(i -> System.out.println(i));
}
}
Retrieve student record based on student id and return that record
Predicate ------> takes inputs ----> returns true or false ===> test ( )
Supplier -----> will not take any input---> returns output ===> get ( )
Consumer ----> will take input ----> will not return anything ===> accept ( )
Function -----> will take input ---> will return output ===> apply ( )
Function Functional Interface
-> Function is predefined functional interface
-> Funcation interface having one abstract method i.e apply(T r)
interface Function<R,T>{
R apply (T t);
-> It takes input and it returns output
package in.azinit;
import java.util.function.BiFunction;
import java.util.function.Function;
public class FunctionDemo {
public static void main(String[] args) {
Function<String, Integer> f = (name) -> name.length();
System.out.println(f.apply("Prakash"));
System.out.println(f.apply("Delhi"));
System.out.println(f.apply("system"));
BiFunction<Integer, Integer, Integer> bifunction = (a, b) -> a
+ b;
System.out.println(bifunction.apply(10, 20));
}
}
Task : Take 2 inputs and perform sum of two inputs and return ouput
BiFunction<Integer, Integer, Integer> bifunction = (a, b) -> a + b;
System.out.println(bifunction.apply(10, 20));
Method References
-> Method reference means Reference to one method from another method
package in.azinit;
@FunctionalInterface
interface MyInterface{
public void m1();
}
public class MethodRef {
public static void m2() {
System.out.println("This is m2() method");
}
public static void main(String[] args) {
MyInterface mi = MethodRef::m2;
mi.m1();
}
}
package in.azinit;
public class InstanceMethodRef {
public void m1() {
for(int i=1; i<=5; i++) {
System.out.println(i);
}
}
public static void main(String[] args) {
InstanceMethodRef im = new InstanceMethodRef();
Runnable r = im::m1;
Thread t = new Thread(r);
t.start();
}
package in.azinit;
import java.util.function.Supplier;
public class Test {
public static void main(String[] args) {
//Doctor d = new Doctor();
Supplier<Doctor> s = Doctor::new;
System.out.println(s.get().hashCode());
class Doctor {
public Doctor() {
System.out.println("Doctor constructor...");
}
Task: WAJP to print numbers from 1 to 5 using Thread with the help of Runnable
interface
package in.azinit;
//Approach-1
public class ThreadDemo1 implements Runnable {
@Override
public void run() {
for(int i=1; i<=5; i++) {
System.out.println(i);
}
public static void main(String[] args) {
ThreadDemo1 td = new ThreadDemo1();
Thread t = new Thread(td);
t.start();
}
}
package in.azinit;
//Approach-2
public class ThreadDemo2 {
public static void main(String[] args) {
Runnable r = new Runnable() {
@Override
public void run() {
for(int i=1; i<=5; i++) {
System.out.println(i);
}
}
};
Thread t = new Thread(r);
t.start();
}
package in.azinit;
//Approach - 3 using Lambda Expression
public class ThreadDemo3 {
public static void main(String[] args) {
Runnable r = () -> {
for(int i=1; i<=5; i++) {
System.out.println(i);
}
};
Thread t = new Thread(r);
t.start();
Task: WAJP to store numbers in ArrayList and sort numbers in descending order
package in.azinit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class NumberSort1 {
public static void main(String[] args) {
ArrayList<Integer> al = new ArrayList<>();
al.add(5);
al.add(3);
al.add(4);
al.add(1);
al.add(2);
System.out.println("Before Sort : " +al);
Collections.sort(al, new NumberCompartor());
System.out.println("After Sort :: " + al);
class NumberCompartor implements Comparator<Integer>{
@Override
public int compare(Integer i, Integer j) {
if(i>j) {
return -1;
} else if(i < j) {
return 1;
}
return 0;
}
}
//Approach -2 (with Lambda)
package in.azinit;
import java.util.ArrayList;
import java.util.Collections;
public class NumberSort2 {
public static void main(String[] args) {
ArrayList<Integer> al = new ArrayList<>();
al.add(5);
al.add(3);
al.add(4);
al.add(1);
al.add(2);
System.out.println("Before Sort :: " +al);
//Collections.sort(al, (i, j) -> i.compareTo(j));
Collections.sort(al, (i, j) -> (i > j) ? -1 : 1);
System.out.println("After Sort :: " + al);
forEach (Consumer c) method
-> forEach (Consumer c) method introduced in java 1.8v
-> forEach ( ) method added in Iterable interface
-> forEach ( ) method is a default method (it is having body)
-> This is method is used to access each element of the collection (traverse collection
from start to end)
package in.azinit;
import java.util.ArrayList;
public class ForEach {
public static void main(String[] args) {
ArrayList<Integer> al = new ArrayList<>();
al.add(5);
al.add(3);
al.add(4);
al.add(1);
al.add(2);
al.forEach(i -> System.out.println(i));
StringJoiner
-> java.util.StringJoiner class introduced in java 1.8v
-> It is used to join more than one String with specified delimiter
-> We can concat prefix and suffix while joininging strings using StringJoiner
StringJoiner sj = new StringJoiner (CharSequence delim);
StringJoiner sj = new StringJoiner (CharSequence delim, CharSequence prefix,
CharSequence suffix);
package in.azinit;
import java.util.StringJoiner;
public class StringJoinerDemo {
public static void main(String[] args) {
StringJoiner sj1 = new StringJoiner("-");
sj1.add("Prakash");
sj1.add("chaurasiya");
sj1.add("It");
sj1.add("Java");
System.out.println(sj1);
StringJoiner sj2 = new StringJoiner("-", "[", "]");
sj2.add("Prakash");
sj2.add("chaurasiya");
sj2.add("It");
sj2.add("Java");
System.out.println(sj2);
}
Optional Class
-> java.util.Optional class introduced in java 1.8v
-> Optional class is used to avoid NullPointerExceptions in the program
Q) What is NullPointerException (NPE)?
Ans) when we perform some operation on null value then we will get
NullPointerException
String s = null;
s.length ( ); // NPE
-> To avoid NullPointerExceptions we have to implement null check before
performing operation on the Object like below.
String s = null;
if( s! = null ) {
System.out.println(s.length ( ));
}
Note: In project there is no gaurantee that every programmer will implement null
checks. If any body forgot to implement null check then program will run into
NullPointerException.
-> To avoid this problem we need to use Optional class like below.
package in.azinit;
import java.util.Optional;
public class User {
//Without Optional object
public String getUsernameById(Integer id) {
if(id == 100) {
return "Raju";
} else if(id == 101) {
return "Rani";
} else if(id == 102) {
return "John";
} else {
return null;
}
//Without Optional Object
public Optional<String> getUsername(Integer id) {
String name = null;
if(id == 100) {
name = "Raju";
} else if(id == 101) {
name = "Rani";
} else if(id == 102) {
name = "John";
}
return Optional.ofNullable(name);
}
}
package in.azinit;
import java.util.Optional;
import java.util.Scanner;
public class MsgService {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println("Enter User ID");
int userId = s.nextInt();
User u = new User();
// String userName = u.getUsernameById(userId);
//
// if(userName != null) {
// String msg = userName.toUpperCase() + ", Hello";
//
// System.out.println(msg);
// } else {
// System.out.println("Invalid ID");
// }
Optional<String> username = u.getUsername(userId);
if(username.isPresent()) {
String name = username.get();
System.out.println(name.toUpperCase()+", Hello");
}else {
System.out.println("NO Data Found");
}
Date & Time API Changes
-> In java we have below 2 classes to represent Date
1) java.util.Date
2) java.sql.Date
Note: When we are performing database operations then we will use java.sql.Date
class.
-> For normal Date related operations we will use java.util.Date class
Date d = new Date ( );
System.out.prinln(d);
Note: When we create Object for Date class, it will represent both date and time.
-> If we want to get only date or only time then we need to format it using
SimpleDateFormat class.
java.text.SimpleDateFormat
-> SimpleDateFormat is a predefined class in java.text pacakage
-> This class provided methods to perform Date conversions
Date to String conversion ===> String format (Date d)
String to Date conversion ===> Date parse(String str)
//Date Conversions Example
package in.azinit;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateDemo {
public static void main(String[] args)throws Exception {
Date d = new Date();
System.out.println(d);
//Converting Date to String
SimpleDateFormat sdf1 = new SimpleDateFormat("dd/MM/yyyy");
String format1 = sdf1.format(d);
System.out.println(format1);
SimpleDateFormat sdf2 = new SimpleDateFormat("MM/dd/yyyy");
String format2 = sdf2.format(d);
System.out.println(format2);
//Convert String to Date
SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd");
Date parsedDate = sdf3.parse("2025-04-13");
System.out.println(parsedDate);
}
}
=> To overcome the problems of java.util.Date class java 1.8 introduced Date API
changes
=> In java 1.8 version, new classes got introduced to deal with Date & Time
functionalities
1) java.time.LocalDate (it will deal with only date)
2) java.time.LocalTime (it will deal with only time)
3) java.time.LocalDateTime (it will deal with both date &
time)
//Java 1.8 Date API Example
package in.azinit;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.util.Date;
public class NewDateDemo {
public static void main(String[] args) {
Date d1 = new Date();
System.out.println(d1);
LocalDate of = LocalDate.of(2021, 1, 23);
System.out.println(of);
LocalDate d2 = LocalDate.now();
System.out.println(d2);
d2 = d2.plusDays(3);
System.out.println(d2);
d2 = d2.plusMonths(1);
System.out.println(d2);
d2 = d2.plusYears(2);
System.out.println(d2);
boolean leapYear = LocalDate.parse("2020-02-22").isLeapYear();
System.out.println("Leap Year :: " + leapYear);
boolean before = LocalDate.parse("2021-12-
22").isBefore(LocalDate.parse("2022-12-22"));
System.out.println("Before : " +before);
LocalTime time = LocalTime.now();
System.out.println(time);
time = time.plusHours(2);
System.out.println(time);
LocalDateTime datetime = LocalDateTime.now();
System.out.println(datetime);
Period between = Period.between(LocalDate.parse("2001-08-23"),
LocalDate.now());
System.out.println(between);
Duration duration = Duration.between(LocalTime.parse("12:00"),
LocalTime.now());
System.out.println(duration);
}
1) What are new changes in java 8 version
2) Interface Changes
2.1 ) Default Methods
2.2 ) Static Methods
3) Why Default & Static method introduced in java 8
4) Lambda Expressions Introduction
5) How to write Lambda Expression
6) How to invoke lambda expression
7) Functional Interfaces
7.1) Predicate & BiPredicate
7.2) Supplier
7.3) Consumer & BiConsumer
7.4) Function & BiFunction
8) Collections Sorting using Lambda
9) Thread Creation Using Lambda
10) Method References & Constructor References
11) java.util.StringJoiner class
12) java.utils.Optional class
13) forEach ( Consumer c ) method
14) Date & Time API Changes
14.1) LocalDate
14.2) LocalTime
14.3) LocalDateTime
14.4) Period
14.5) Duration
Stream API
-> Stream API introduced in java 1.8v
-> Stream API is used to process the data
Note: Collections are used to store the data
-> Stream API is one of the major features added in java 1.8v
-> Stream in java can be defined as sequence of elements that comes from a source.
-> Source of data for the Stream can be array or collection
Few Important Points About Streams
1) Stream is not a data structure. Stream means bunch of operations applied on
source data. Source can be collection or array.
2) Stream will not change original data structure of the source (It will just process the
data given by the source.)
Stream Creation
-> In Java we can create Stream in 2 ways
1) Stream.of (e1, e2, e3, e4.....)
2) stream ( ) method
//Java Program to Create Stream
package in.azinit;
import java.util.ArrayList;
import java.util.stream.Stream;
public class FirstDemo {
public static void main(String[] args) {
//Approach-1
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
ArrayList<String> names = new ArrayList<>();
names.add("John");
names.add("Robert");
names.add("Orlen");
//Approach-2
Stream<String> stream2 = names.stream();
}
Stream Operations
-> Stream API provided several methods to perform Operations on the data
-> We can divide Stream api methods into 2 types
1) Intermediate Operational Methods
2) Terminal Operational Methods
-> Intermediate Operational methods will perform operations on the stream and
returns a new Stream
Ex: filter ( ), map ( ) etc....
-> Terminal Operational methods will take input and will provide result as output.
Ex: count ( )
Filtering with Streams
-> Filtering means getting required data from original data
Ex: get only even numbers from given numbers
Ex: get emps whose salary is >= 1,00,000
Ex: Get Mobiles whose price is <= 15,000
-> To apply filter on the data, Stream api provided filter ( ) method
Ex: Stream filter (Predicate p)
Example - 1: Filter
package in.stream.revision;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class FirstDemo1 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(66, 32, 45, 12, 20);
// for(Integer i : list) {
// if(i > 20) {
// System.out.println(i);
// }
// }
// Stream<Integer> stream = list.stream();
// Stream<Integer> filteredStream = stream.filter(i -> i > 20);
// filteredStream.forEach(i -> System.out.println(i));
list.stream().filter(i -> i > 20).forEach(i ->
System.out.println(i));
}
}
Example - 2 : Filter
package in.stream.revision;
import java.util.Arrays;
import java.util.List;
public class FirstDemo {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Anushka",
"Anupama", "Smith", "Ashok");
names.stream().filter(i -> i.startsWith("A")).forEach(i ->
System.out.println(i));
Example - 3 : Filter
package in.stream.revision;
import java.util.stream.Stream;
public class FirstDemo2 {
public static void main(String[] args) {
User u1 = new User("Anushka", 25);
User u2 = new User("Smith", 30);
User u3 = new User("Raju", 15);
User u4 = new User("Rani", 10);
User u5 = new User("Charles", 35);
User u6 = new User("Ashok", 30);
Stream<User> stream = Stream.of(u1, u2, u3, u4, u5, u6);
//stream.filter(u -> u.age >= 18).forEach(u ->
System.out.println(u));
//stream.filter(u -> u.age >= 18 &&
u.name.startsWith("A")).forEach(u -> System.out.println(u));
stream.filter(u -> u.age >= 18)
.filter(u -> u.name.startsWith("A"))
.forEach(u -> System.out.println(u));
class User{
String name;
int age;
User(String name, int age){
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
Mapping Operations
-> Mapping operations are belongs to intermediate operations in the Stream api
-> Mapping operations are used to transform the stream elements and return
transformed elements as new Stream
Ex : Stream map (Function function) ;
Example-1 : map ( ) method
package in.stream.revision;
import java.util.Arrays;
import java.util.List;
public class FirstDemo3 {
public static void main(String[] args) {
List<String> names = Arrays.asList("india", "usa", "uk",
"japan");
/*for(String name : names) {
System.out.println(name.toUpperCase());
}*/
names.stream().map(name -> name.toUpperCase()).forEach(n ->
System.out.println(n));
names.stream().mapToInt(name -> name.length()).forEach(n ->
System.out.println(n));
}
Example-2 : map ( ) method
package in.stream.revision;
import java.util.Arrays;
import java.util.List;
public class FirstDemo4 {
public static void main(String[] args) {
List<String> names = Arrays.asList("Ashok", "Anil", "Raju",
"Rani", "John", "Akash");
//print name with its length which are starting with 'A' using
Stream API
//Ashok - 5
//Anil - 4
//Akash - 5
names.stream()
.filter(i -> i.startsWith("A"))
.map(n -> n+"-"+n.length())
.forEach(name -> System.out.println(name));
Example-3 : map ( ) method
class Employee ( ) {
String name; int age; double salary;
Task: Print Emp Name with Emp age whose salary is >= 50,000 using Stream API.
package in.stream.revision;
import java.util.stream.Stream;
public class FirstDemo5 {
public static void main(String[] args) {
Employee e1 = new Employee("John", 35, 55000.00);
Employee e2 = new Employee("David", 25, 25000.00);
Employee e3 = new Employee("Buttler", 45, 45000.00);
Employee e4 = new Employee("Steve", 55, 35000.00);
Employee e5 = new Employee("Gojo", 15, 65000.00);
Stream<Employee> stream = Stream.of(e1, e2, e3, e4, e5);
/*stream.filter(e -> e.salary >= 50000.00)
.map(e -> e.name+" - "+ e.age)
.forEach(e -> System.out.println(e));*/
stream.filter(e -> e.salary >= 50000.00)
.forEach(e -> System.out.println(e.name+" "+e.age));
}
}
class Employee {
String name;
int age;
double salary;
public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
}
Q) What is flatMap(Function f) method ?
-> It is used to flaten list of streams into single stream
package in.stream.revision;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class FirstDemo6 {
public static void main(String[] args) {
List<String> javaCourse = Arrays.asList("CoreJava", "AdvJava",
"SpringBoot");
List<String> uiCourse = Arrays.asList("html", "css", "bs",
"js");
List<List<String>> course = Arrays.asList(javaCourse,
uiCourse);
//course.stream().forEach(c -> System.out.println(c));
Stream<String> fms = course.stream().flatMap(s -> s.stream());
fms.forEach(c -> System.out.println(c));
}
Slicing Operations with Stream
1) distinct ( ) => To get unique elements from the Stream
2) limit ( long maxSize ) => Get elements from the stream based on given size
3) skip (long n) => It is used to skip given number of elements from starting position
of the stream
Note: All the above 3 methods are comes under Intermediate Operational Methods.
They will perform operation and returns new Stream.
package in.stream.revision;
import java.util.Arrays;
import java.util.List;
public class FirstDemo7 {
public static void main(String[] args) {
List<String> javaCourses = Arrays.asList("corejava",
"advjava", "springboot", "restapi", "microservices");
javaCourses.stream().limit(3).forEach(c ->
System.out.println(c));
javaCourses.stream().skip(3).forEach(c ->
System.out.println(c));
List<String> names = Arrays.asList("raja", "rani", "raja",
"rani");
names.stream().distinct().forEach(name ->
System.out.println(name));
}
Matching Operations with Stream
1) boolean anyMatch (Predicate p )
2) boolean allMatch (Predicate p )
3) boolean noneMatch (Predicate p )
Note: The above 3 methods are belongs to Terminal Operations because they will do
operation and they will return result directly (they won't return stream)
-> The above methods are used to check the given condition and returns true or false
value based on condition.
package in.stream.revision;
import java.util.Arrays;
import java.util.List;
public class FirstDemo8 {
public static void main(String[] args) {
Person p1 = new Person("john", "USA");
Person p2 = new Person("Steve", "JAPAN");
Person p3 = new Person("ashok", "INDIA");
Person p4 = new Person("Ching", "CHINA");
List<Person> persons = Arrays.asList(p1 ,p2, p3, p4);
boolean status1 = persons.stream().anyMatch(p ->
p.country.equals("INDIA"));
System.out.println("Any Indian Avilable ? :: "+status1);
boolean status2 = persons.stream().anyMatch(p ->
p.country.equals("CANADA"));
System.out.println("Any Indian Avilable ? :: "+status2);
boolean status3 = persons.stream().allMatch(p ->
p.country.equals("INDIA"));
System.out.println("Any Indian Avilable ? :: "+status3);
boolean status4 = persons.stream().noneMatch(p ->
p.country.equals("MEXICO"));
System.out.println("Any Indian Avilable ? :: "+status4);
class Person {
String name;
String country;
public Person(String name, String country) {
this.name = name;
this.country = country;
}
Collectors with Stream
-> Collectors are used to collect data from Stream
Example-1 : Collectors
package in.stream.revision;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class FirstDemo9 {
public static void main(String[] args) {
Person1 p1 = new Person1("John", "USA");
Person1 p2 = new Person1("Steve", "JAPAN");
Person1 p3 = new Person1("Ashok", "INDIA");
Person1 p4 = new Person1("ching", "CHINA");
Person1 p5 = new Person1("Kumar", "INDIA");
Person1 p6 = new Person1("Gojo", "JAPAN");
List<Person1> person = Arrays.asList(p1, p2, p3, p4, p5, p6);
List<Person1> indians = person.stream().filter(p ->
p.country.equals("INDIA")).collect(Collectors.toList());
indians.forEach(i -> System.out.println(i));
class Person1{
String name;
String country;
public Person1(String name, String country) {
this.name = name;
this.country = country;
}
@Override
public String toString() {
return "Person1 [name=" + name + ", country=" + country + "]";
}
Example-2: Collectors
package in.stream.revision;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class FirstDemo10 {
public static void main(String[] args) {
Person2 p1 = new Person2("John", "USA");
Person2 p2 = new Person2("Steve", "JAPAN");
Person2 p3 = new Person2("Ashok", "INDIA");
Person2 p4 = new Person2("ching", "CHINA");
Person2 p5 = new Person2("Kumar", "INDIA");
Person2 p6 = new Person2("Gojo", "JAPAN");
List<Person2> person = Arrays.asList(p1, p2, p3, p4, p5, p6);
//collect names of persons who are belongs to india and store
into names collection
List<String> names = person.stream().filter(p ->
p.country.equals("INDIA")).map(p -> p.name).collect(Collectors.toList());
System.out.println(names);
}
class Person2{
String name;
String country;
public Person2(String name, String country) {
this.name = name;
this.country = country;
}
@Override
public String toString() {
return "Person1 [name=" + name + ", country=" + country + "]";
}
}
Set - 1 : Intermediate Operations (will return Stream)
Filters ----> filter ( )
Mappings ----> map ( ) & flatMap ( )
Slicing ----> distinct ( ) & limit () & skip ( )
Set - 2 : Terminal Operations (will return result)
Finding ---> findFirst ( ) & findAny ( )
Matching ---> anyMatch ( ) & allMatch ( ) & noneMatch ( )
Collecting ---> collect ( )
Requirement
=> Write a java program to get MAX, MIN and AVG salary from given employees data
using Stream API.
package in.stream.revision;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class FirstDemo11 {
public static void main(String[] args) {
Employee1 e1 = new Employee1(1, "Robert", 26500.00);
Employee1 e2 = new Employee1(2, "Abraham", 46500.00);
Employee1 e3 = new Employee1(3, "Ching", 36500.00);
Employee1 e4 = new Employee1(4, "David", 16500.00);
Employee1 e5 = new Employee1(5, "Cathy", 25500.00);
List<Employee1> list = Arrays.asList(e1, e2, e3, e4, e5);
Optional<Employee1> max =
list.stream().collect(Collectors.maxBy(Comparator.comparing(e ->
e.salary)));
System.out.println("Max Salary :: "+max.get().salary);
Optional<Employee1> min =
list.stream().collect(Collectors.minBy(Comparator.comparing(e ->
e.salary)));
System.out.println("Min Salary :: "+min.get().salary);
Double avgSalary =
list.stream().collect(Collectors.averagingDouble(e -> e.salary));
System.out.println("AvgSalary :: "+avgSalary);
class Employee1 {
int id;
String name;
double salary;
public Employee1(int id, String name, double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
Group By using Stream
-> Group By is used categorize the data / Grouping the data
-> When we use groupingBy ( ) function with stream they it will group the data as
Key-Value(s) pair and it will return Map object
-> In below example employees will be grouped based on Country name.
package in.stream.revision;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class FirstDemo12 {
public static void main(String[] args) {
Employee2 e1 = new Employee2(1, "Robert", 26500.00, "USA");
Employee2 e2 = new Employee2(2, "Abraham", 46500.00, "INDIA");
Employee2 e3 = new Employee2(3, "Ching", 36500.00, "CHINA");
Employee2 e4 = new Employee2(4, "David", 16500.00, "INDIA");
Employee2 e5 = new Employee2(5, "Cathy", 25500.00, "USA");
List<Employee2> list = Arrays.asList(e1, e2, e3, e4, e5);
Map<String, List<Employee2>> data =
list.stream().collect(Collectors.groupingBy(e -> e.country));
System.out.println(data);
}
class Employee2 {
int id;
String name;
double salary;
String country;
public Employee2(int id, String name, double salary, String country)
{
this.id = id;
this.name = name;
this.salary = salary;
this.country = country;
@Override
public String toString() {
return "Employee2 [id=" + id + ", name=" + name + ", salary="
+ salary + ", country=" + country + "]";
}
Parallel Streams
-> Generally Streams will execute in sequence order
-> To improve execution process of the stream we can use parallel streams
-> Parallel Streams introduced to improve performance of the program.
package in.stream.revision;
import java.util.stream.Stream;
public class ParallelDemo {
public static void main(String[] args) {
System.out.println("===Serial Stream===");
Stream<Integer> ss = Stream.of(1, 2, 3, 4);
ss.forEach(n -> System.out.println(n+" ::
"+Thread.currentThread()));
System.out.println("===Parallel Stream===");
Stream<Integer> ps = Stream.of(1, 2, 3, 4);
ps.parallel().forEach(n -> System.out.println(n+" ::
"+Thread.currentThread()));
Java Spliterator
-> Like Iterator and ListIterator, Spliterator is one of the Java Iterator
-> Spliterator introduced in java 1.8v
-> Spliterator is an interface in collections api
-> Spliterator supports both serial & paralell programming
-> Spliterator we can use to traverse both Collections & Streams
-> Spliterator can't be used with Map implementation classes
package in.stream.revision;
import java.util.Arrays;
import java.util.List;
import java.util.Spliterator;
public class ParallelDemo1 {
public static void main(String[] args) {
List<String> names = Arrays.asList("sachin", "sehwag",
"dhoni");
Spliterator<String> spliterator =
names.stream().spliterator();
spliterator.forEachRemaining(n -> System.out.println(n));
Stream Reduce
package in.stream.revision;
import java.util.Arrays;
public class Sum {
public static void main(String[] args) {
int nums[] = {1, 2, 3, 4, 5};
/*int sum = 0;
for(int i : nums) {
sum = sum + i;
}
System.out.println(sum);*/
int reduce = Arrays.stream(nums).reduce(0, (a,b) -> a+b);
System.out.println(reduce);
}
Nashorn Engine in Java 1.8
-> Nashorn is a Java Script Engine which is used to execute Java Script code using JVM
-> Create a javascript file like below (filename : one.js)
--------------------- one.js --------------------------
var hello = function(){
print("Welcome to JavaScript");
hello();
------------------------------------------------------
-> Open command prompt and execute below command
syntax : jjs one.js
-> We can execute above Java Script file using Java program like below
package in.hisokait;
import java.io.*;
import javax.script.*;
public class Demo {
public static void main(String[] args) throws Exception {
ScriptEngine se = new
ScriptEngineManager().getEngineByName("Nashorn");
se.eval(new FileReader("one.js"));
}
I/O Streams Changes in Java 8
Task: Write a java program to read a file data and print it on the console
-> To read file data we can use FileReader & BufferedReader classes
FileReader ----> It will read the data character by character (slow performance)
BufferedReader ---> It will read the data line by line
Files.lines(Path path) ---> It will read all lines at a time and returns as a Stream
package in.hisokait;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class ReadFileData {
public static void main(String[] args) throws Exception {
// FileReader fr = new FileReader(new File("info.txt"));
//
// BufferedReader br = new BufferedReader(fr);
//
// String line = br.readLine();
//
// while(line!=null) {
// System.out.println(line);
// line = br.readLine();
// }
//
// br.close();
String filename = "info.txt";
List<String> lines = new ArrayList<>();
try(Stream<String> stream =
Files.lines(Paths.get(filename))){
//stream.forEach(line -> System.out.println(line));
stream.filter(line -> line.startsWith("H")).forEach(line
-> System.out.println(line));
}catch(Exception e) {
e.printStackTrace();
}
}
Java 8 Base64 Changes
-> Base64 is a predefined class available in java.util package
-> Base64 class providing methods to perform encoding and decoding
Encoder encoder = Base64.getEncoder();
// converting String to byte[] and passing as input for encode( ) method
byte[] encode = encoder.encode(pwd.getBytes());
// Converting byte[] to String
String encodedPwd = new String(encode);
System.out.println(encodedPwd);
Decoder decoder = Base64.getDecoder();
byte[ ] decode = decoder.decode(encodedPwd);
String decodedPwd = new String(decode);
System.out.println(decodedPwd);
Example:
package in.hisokait;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
public class PasswordService {
public static void main(String[] args) throws Exception {
String pwd = "prakash@23";
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte digest[] = md.digest(pwd.getBytes());
String str = new String(digest);
System.out.println(str);
// Encoder encoder = Base64.getEncoder();
//
// //Converting string to byte[] and passing as input for
encode() method
// byte encode[] = encoder.encode(pwd.getBytes());
//
// //Converting byte[] to String
// String encodedPwd = new String(encode);
// System.out.println(encodedPwd);
//
// Decoder decoder = Base64.getDecoder();
//
// byte decode[] = decoder.decode(encodedPwd);
// String decodedPwd = new String(decode);
// System.out.println(decodedPwd);
}
Stream API Question
package in.hisokait;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
public class EmpData {
public static void main(String[] args) {
List<Employee> emps = new ArrayList<Employee>();
emps.add(new Employee(1, "Jhansi", 32, "Female", "HR", 2011,
25000.0));
emps.add(new Employee(2, "Smith", 25, "Male", "Sales", 2015,
13500.0));
emps.add(new Employee(3, "David", 29, "Male",
"Infrastructure", 2012, 18000.0));
emps.add(new Employee(4, "Orlen", 28, "Male", "Development",
2014, 32500.0));
emps.add(new Employee(5, "Charles", 27, "Male", "HR", 2013,
22700.0));
emps.add(new Employee(6, "Cathy", 43, "Male", "Security",
2016, 10500.0));
emps.add(new Employee(7, "Ramesh", 35, "Male", "Finance",
2010, 27000.0));
emps.add(new Employee(8, "Suresh", 31, "Male", "Development",
2015, 34500.0));
emps.add(new Employee(9, "Gita", 24, "Female", "Sales", 2016,
11500.0));
emps.add(new Employee(10, "Mahesh", 38, "Male", "Security",
2015, 11000.5));
emps.add(new Employee(11, "Gouri", 27, "Female",
"Infrastructure", 2014, 15700.0));
emps.add(new Employee(12, "Nithin", 25, "Male", "Development",
2016, 28200.0));
emps.add(new Employee(13, "Swathi", 27, "Female", "Finance",
2013, 21300.0));
emps.add(new Employee(14, "Buttler", 24, "Male", "Sales",
2017, 10700.5));
emps.add(new Employee(15, "Ashok", 23, "Male",
"Infrastructure", 2018, 12700.0));
emps.add(new Employee(16, "Sanvi", 26, "Female",
"Development", 2015, 28900.0));
//1. How many male and female employees are there in the
organization ?
Map<String, Long> map1 =
emps.stream().collect(Collectors.groupingBy(Employee::getGender,
Collectors.counting()));
System.out.println(map1);
//2. Print the name of all departments in the organization ?
emps.stream().map(e -> e.department).distinct().forEach(name -
> System.out.println(name));
//3. What is the average age of male and female employees ?
Map<String, Double> map2 =
emps.stream().collect(Collectors.groupingBy(Employee::getGender,
Collectors.averagingInt(Employee::getAge)));
System.out.println(map2);
//4. Get the details of highest paid employee in the
organization ?
Optional<Employee> optional1 =
emps.stream().collect(Collectors.maxBy(Comparator.comparing(Employee::get
Salary)));
if(optional1.isPresent()) {
Employee employee = optional1.get();
System.out.println(employee);
}
//5. Get the names of all employees who have joined after 2015
?
emps.stream().filter(e -> e.yearOfJoining > 2015).map(e ->
e.name).forEach(name -> System.out.println(name));
//6. Count the number of employees in each department ?
Map<String, Long> map3 =
emps.stream().collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.counting()));
System.out.println(map3);
//7. What is the average salary of each department ?
Map<String, Double> map4 =
emps.stream().collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.averagingDouble(Employee::getSalary)));
System.out.println(map4);
//8. Get the details of youngest male employee in the
Development department ?
Optional<Employee> optional2 = emps.stream().filter(e ->
e.getGender().equals("Male") &&
e.getDepartment().equals("Development")).min(Comparator.comparing(Employe
e::getAge));
if(optional2.isPresent()) {
System.out.println(optional2.get());
}
//9. Who has the most working experience in the organization ?
Optional<Employee> optional3 =
emps.stream().collect(Collectors.minBy(Comparator.comparing(Employee::get
YearOfJoining)));
if(optional3.isPresent()) {
System.out.println(optional3.get());
}
//10. How many male and female employees are there in the
Sales team ?
Map<String, Long> map5 = emps.stream().filter(e ->
e.getDepartment().equals("Sales")).collect(Collectors.groupingBy(Employee
::getGender, Collectors.counting()));
System.out.println(map5);
//11. What is the average salary of male and female employees
?
//12. List down the names of all employees in each department
?
//13. What is the average salary and total salary of the
whole organization ?
//14. Separate the employees who are younger or equal to 25
years from those employees who are older than 25 years ?
//15. Who is the oldest employee in the organization?
//16. Get the Employee who is get second highest salary?
// sort Employee based on salary descending order then skip
first record
Optional<Employee> findFirst =
emps.stream().sorted(Comparator.comparing(Employee::getSalary).reversed()
).skip(1).findFirst();
System.out.println(findFirst.get());
//Second way
List<Employee> collect =
emps.stream().sorted(Comparator.comparing(Employee::getSalary).reversed()
).collect(Collectors.toList());
System.out.println(collect.get(1));
}
class Employee
{
int id;
String name;
int age;
String gender;
String department;
int yearOfJoining;
double salary;
// constructor
public Employee(int id, String name, int age, String gender, String
department, int yearOfJoining, double salary) {
super();
this.id = id;
this.name = name;
this.age = age;
this.gender = gender;
this.department = department;
this.yearOfJoining = yearOfJoining;
this.salary = salary;
// getters and setters
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public int getYearOfJoining() {
return yearOfJoining;
}
public void setYearOfJoining(int yearOfJoining) {
this.yearOfJoining = yearOfJoining;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", age=" +
age + ", gender=" + gender + ", department="
+ department + ", yearOfJoining=" + yearOfJoining +
", salary=" + salary + "]";
}