1. What is the Difference between Map and Filter?
    Both perform intermediate Operations and returns stream as output.By using map, you transform the object values.
    Map returns a stream consisting of the results of applying the given function to the elements of this stream. In a simple sentence, the map returns the transformed object value.
    Filter is used for filtering the data, it always returns the boolean value. If it returns true, the item is added to list else it is filtered out (ignored)
  2. Find the Sum of Nos in List?
    public class ReduceEgs {
        public static void main(String[] args) {
            List<Integer> arrNumbers =  Arrays.asList(1,2,3,4,5,6,7,8,9);
    
            Integer sum = arrNumbers.stream().reduce(0, Integer::sum);
            Integer sum2 = arrNumbers.stream().reduce(0, (x,y)->x+y);
            Integer sum3 = arrNumbers.stream().reduce(0, ReduceEgs::sumNos);
        }
    
        public static Integer sumNos(int x, int y){
            System.out.println("a -"+ x + " b - "+  y);
            return x+y;
        }
    }
    
  3. Find the Min and Max in Nos List?
     public static void main(String[] args) {
            List<Integer> arrNumbers =  Arrays.asList(1,2,3,4,5,-6,7,-8,9);
    
            arrNumbers =  Arrays.asList(-5,-6,-8);
            Integer Max = arrNumbers.stream().reduce(0, (x,y)->x>y?x:y);
            System.out.println("Output 1 ="+ Max);
    
            //Its good to start with Identity as Negative Value in order to address negative Integer Comparison
            //If you start with 0 then 0 would be returned like above
            Integer Max2 = arrNumbers.stream().reduce(Integer.MIN_VALUE, (x,y)->x>y?x:y);
            System.out.println("Output 2 ="+ Max2);
    
            arrNumbers =  Arrays.asList(5,6,8);
    
            Integer Min = arrNumbers.stream().reduce(0, (x,y)->x<y?x:y);
            System.out.println("Output 3 ="+ Min);
    
            //Its good to start with Identity as Max Positive Value in order to address Integer Comparison
            Integer Min2 = arrNumbers.stream().reduce(Integer.MAX_VALUE, (x,y)->x<y?x:y);
            System.out.println("Output 4 ="+ Min2);
        }
    

    Output

    Output 1 =0
    Output 2 =-5
    Output 3 =0
    Output 4 =5
    
  4. Find the Sum of Square of Nos in List?
    public class ReduceEgs {
        public static void main(String[] args) {
            List<Integer> arrNumbers =  Arrays.asList(1,2,3);
    
            Integer squareSum = arrNumbers.stream().map(x->x*x).reduce(0, Integer::sum);
            System.out.println("Output 1 ="+ squareSum);
        }
    }
    

    Output

    Output 1 =14
    
  5. Find the Sum of Odd Nos in List?
    public class ReduceEgs {
        public static void main(String[] args) {
            List<Integer> arrNumbers =  Arrays.asList(1,2,3);
    
            Integer squareSum = arrNumbers.stream().filter(x-> x%2==1).reduce(0, Integer::sum);
            System.out.println("Output 1 ="+ squareSum);
        }
    }
    

    Output

    Output 1 =4
    
  6. Distinct elements from List?
    public class ReduceEgs {
        public static void main(String[] args) {
            List<Integer> arrNumbers =  Arrays.asList(1,2,3,1,4,2);
    
            System.out.println("Output 1");
            arrNumbers.stream().distinct().forEach(System.out::println);
        }
    }
    
    

    Output

    Output 1
    1
    2
    3
    4
    
  7. Sort Elements in List?
     public static void main(String[] args) {
       List<Integer> arrNumbers =  Arrays.asList(1,2,3,1,4,2);
    
       System.out.println("Output 2");
       arrNumbers.stream().sorted().forEach(System.out::println);
    }
    

    Output

    Output 2
    1
    1
    2
    2
    3
    4
    
  8. Sorting based on Natural Order, Reverse Order and Length of String?
    public static void main(String[] args) {
            List<String> arrSkills = Arrays.asList("Java", "Python",  "Ant");
    
            System.out.println("Sorting in Natural Order");
            arrSkills.stream().sorted(Comparator.naturalOrder()).forEach(System.out::println);
    
            System.out.println("Sorting in Reverse Order");
            arrSkills.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
    
            System.out.println("Sorting based on Length");
            arrSkills.stream().sorted(Comparator.comparing(str -> str.length())).forEach(System.out::println);
    
        }
    

    Output

    Sorting in Natural Order
    Ant
    Java
    Python
    Sorting in Reverse Order
    Python
    Java
    Ant
    Sorting based on Length
    Ant
    Java
    Python
    
  9. Collect the Elements in the List – Collect Even Nos and Length of String ?
        public static void main(String[] args) {
            List<Integer> arrNumbers = Arrays.asList(1,2,4,5,7,6);
            List<String> arrNames = Arrays.asList("Java", "Oracle", "Maven", "Ant");
    
            System.out.println("Collect Even Nos in list");
            List<Integer> arrEvenNumbers = arrNumbers.stream().filter(x->x%2==0).collect(Collectors.toList());
            arrEvenNumbers.stream().forEach(System.out::println);
    
            System.out.println("Length of Elements");
            List<Integer> arrEvenNumbers2 = arrNames.stream().map(str->str.length()).collect(Collectors.toList());
            arrEvenNumbers2.stream().forEach(System.out::println);
        }
    

    Output

    Collect Even Nos in list
    2
    4
    6
    Length of Elements
    4
    6
    5
    3
    
  10. Find the Sum of Nos in List?
    
    
  11. Find the Sum of Nos in List?
    
    
  12. Find the Sum of Nos in List?
    
    

When to use Lambda Expressions
If you have a functional Interface which has only one Abstract Method then we can use Lambda Expression at the Class which implements the functional interface
and provides the method definition for the abstract method in Functional Interface.

  1. We have a Function Interface Printable with abstract method print
  2. Two classes implements functional Interface – DailyReport and MothlyReport. They provide the method definition for Print() method in Printable Interface
  3. GenerateReport class has a downloadReport method which takes the Printable Type as argument
  4. DownloadReport Class we use the Printable reference and call the exact implementation by passing as argument

Printable.java

@FunctionalInterface
public interface Printable {
    public void print();
}

DailyReport.java

public class DailyReport implements Printable {
    @Override
    public void print() {
        System.out.println("Printing Report in Daily Format");
    }
}

MonthlyReport.java

public class MonthlyReport implements Printable {
    @Override
    public void print() {
        System.out.println("Printing Report in Monthly Format");
    }
}

GenerateReport.java

public class GenerateReport {
    public static void downloadReport(Printable printable){
        printable.print();
    }
}

Without Lambda Expression
DownloadReport.java

public class DownloadReport {
    public static void main(String[] args) {
        GenerateReport objGenReport = new GenerateReport();
        Printable objDailyReport = new DailyReport();
        Printable objMonthlyReport = new MonthlyReport();

        objGenReport.downloadReport(objDailyReport);
        objGenReport.downloadReport(objMonthlyReport);
    }
}

Output

Printing Report in Daily Format
Printing Report in Monthly Format

With Lambda Expression
Using Lambda expression we can pass method definition directly as parameter instead of using a class to extend interface and writing a method definition for the interface method
DownloadReport.java

public class DownloadReport {
    public static void main(String[] args) {
        GenerateReport objGenReport = new GenerateReport();
        objGenReport.downloadReport(() -> System.out.println("Printing Report in Daily Format using Lambda Expr"));

        Printable mnthlyReport = () -> System.out.println("Printing Report in Monthly Format using Lambda Expr");
        objGenReport.downloadReport(mnthlyReport);     
    }
}

Output

Printing Report in Daily Format using Lambda Expr
Printing Report in Monthly Format using Lambda Expr
With Lambda Expression Without Lambda Expression
We pass the method definition as Argument
  1. Method Definition in MonthlyReport.java
  2. Method Definition in DailyReport.java
  3. Object creation for DailyReport and MonthlyReport

Let’s take the below Example where we find the square of even numbers

ReduceEgs.java

public class ReduceEgs {
    public static void main(String[] args) {
        List<Integer> arrNumbers = Arrays.asList(1,2,4,5,7,6);

        arrNumbers.stream()
                  .filter(x-> x%2==0)
                  .map(x->x*x)
                  .forEach(System.out::println);
    }
}

In the above code we have

  1. Filter which takes Predicate as Param
  2. Map which takes Function as Param
  3. Sysout which takes Consumer as Param

The filter, Consumer and sysout have been expanded from the above code as below.

public class ReduceEgs {
        public static void main(String[] args) {
            List<Integer> arrNumbers = Arrays.asList(1,2,4,5,7,6);
    
            arrNumbers.stream()
                      .filter(getIntegerPredicate())
                      .map(getFunction())
                      .forEach(getPrintln());
        }
    
        private static Consumer<Integer> getPrintln() {
            return System.out::println;
        }
    
        private static Function<Integer, Integer> getFunction() {
            return x -> x * x;
        }
    
        private static Predicate<Integer> getIntegerPredicate() {
            return x -> x % 2 == 0;
        }
}

The Above code is refactored as below

public class ReduceEgs {
        public static void main(String[] args) {
            List<Integer> arrNumbers = Arrays.asList(1,2,4,5,7,6);

            Function<Integer, Integer> getSquare = x -> x * x;
            Predicate<Integer>         getEvenNo = x -> x % 2 == 0;
            Consumer<Integer>          showNos   = System.out::println;

            arrNumbers.stream()
                      .filter(getEvenNo)
                      .map(getSquare)
                      .forEach(showNos);
        }
}

What the java compiler does internally changes the above code as below. It created an anonymous inner class for implementing the methods in the interface.

  1. Function has apply method which should be implemented
  2. Consumer has accept method which should be implemented
  3. Predicate has test method which should be implemented
public class ReduceEgs {
        public static void main(String[] args) {
            List<Integer> arrNumbers = Arrays.asList(1,2,4,5,7,6);

            Function<Integer, Integer> getSquare = new Function<Integer, Integer>() {
                @Override
                public Integer apply(Integer integer) {
                    return integer * integer;
                }
            };

            Predicate<Integer> getEvenNo =  new Predicate<Integer>() {
                @Override
                public boolean test(Integer integer) {
                    return  integer % 2 == 0;
                }
            };

            Consumer<Integer> showNos = new Consumer<Integer>() {
                @Override
                public void accept(Integer integer) {
                    System.out.println(integer);
                }
            };

            arrNumbers.stream()
                      .filter(getEvenNo)
                      .map(getSquare)
                      .forEach(showNos);
        }
}

The output of all the above code is one and same as below

4
16
36

We have a Employee Object with following fields – empId,salary,empAge,totalExp,empName,location,pincode. Now we are going to do following operations in the List containing Employee Object.

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class MatchEgs {
    public static void main(String[] args) {
        Employee objEmp1 = new Employee(101, "Mugil", 30, "Chennai", "600018", 5, 5000);
        Employee objEmp2 = new Employee(102, "Mani", 33, "Chennai", "600028", 4, 6000);
        Employee objEmp3 = new Employee(103, "Madhu", 32, "Chennai", "600054", 6, 10000);
        Employee objEmp4 = new Employee(104, "Vinu", 29, "Bangalore", "500234", 5, 15000);
        Employee objEmp5 = new Employee(105, "Srini", 40, "Delhi", "622142", 10, 7000);
        Employee objEmp6 = new Employee(106, "Dimple", 35, "Delhi", "622142", 5, 8000);

        List<Employee> arrEmployee = Arrays.asList(objEmp1, objEmp2, objEmp3, objEmp4, objEmp5, objEmp6);
 }
}

Check if people match the criteria by passing predicate to anyMatch, noneMatch and allMatch

        Predicate<Employee> empAgeGreaterThan35 = employee -> employee.getEmpAge() > 35;
        Predicate<Employee> empAgeGreaterThan30 = employee -> employee.getEmpAge() > 30;
        Predicate<Employee> empStayingInDelhi   = employee -> employee.getLocation().equals("Delhi");

        //Check if Some Employee Age is Greater 30
        System.out.println(arrEmployee.stream().anyMatch(empAgeGreaterThan35));

        //Check if all Employee Age is above 30
        System.out.println(arrEmployee.stream().allMatch(empAgeGreaterThan30));

        //Check if any Employee Location in Delhi
        System.out.println(arrEmployee.stream().noneMatch(empStayingInDelhi));

Sort Employee by Name passing Comparator using Sorted and reversed. Sort based on more than
one field using thenComparing

        Comparator<Employee> sortByName = Comparator.comparing(Employee::getEmpName);
        List<Employee> arrSortedByName = arrEmployee.stream()
                                                    .sorted(sortByName)
                                                    .collect(Collectors.toList());
        System.out.println("----------------Sorted By Name----------------");
        arrSortedByName.forEach(employee -> System.out.println(employee));

        Comparator<Employee> sortByNameReversed = Comparator.comparing(Employee::getEmpName).reversed();
        List<Employee> arrSortedByNameRev = arrEmployee.stream()
                                                       .sorted(sortByNameReversed)
                                                       .collect(Collectors.toList());
        System.out.println("----------------Sorted By Name Reversed----------------");
        arrSortedByNameRev.forEach(employee -> System.out.println(employee));

        Comparator<Employee> sortByNameanAge = Comparator.comparing(Employee::getEmpName).thenComparing(Employee::getEmpAge);
        List<Employee> arrSortedByNameAge = arrEmployee.stream()
                                                       .sorted(sortByNameanAge)
                                                       .collect(Collectors.toList());
        System.out.println("----------------Sorted By Name and Age----------------");
        arrSortedByNameAge.forEach(employee -> System.out.println(employee));

Limit and Skip records using limit and skip

        System.out.println("----------------Limit Records to 3 ----------------");
        List<Employee> arrEmp3 =  arrEmployee.stream()
                                             .limit(3)
                                             .collect(Collectors.toList());
        arrEmp3.forEach(employee -> System.out.println(employee));

        System.out.println("----------------Skip First 3 Records ----------------");
        List<Employee> arrEmp4 =  arrEmployee.stream()
                                             .skip(3)
                                             .collect(Collectors.toList());
        arrEmp4.forEach(employee -> System.out.println(employee));

doWhile when condition is true using takeWhile and vice-versa(Until condition is met) using dropWhile

        System.out.println("----------------Print Records until Chennai - Keeps printing until condition is True----------------");
        List<Employee> arrEmp5 =  arrEmployee.stream()
                                             .takeWhile(employee -> employee.getLocation().equals("Chennai"))
                                             .collect(Collectors.toList());
        arrEmp5.forEach(employee -> System.out.println(employee));

        System.out.println("----------------Print Records until Chennai - Stops printing when condition is Met ----------------");
        List<Employee> arrEmp6 =  arrEmployee.stream()
                                             .dropWhile(employee -> employee.getLocation().equals("Bangalore"))
                                             .collect(Collectors.toList());
        arrEmp5.forEach(employee -> System.out.println(employee));

Get Minimum and Maximum age of employee using min and max. The List should be sorted first using comparator. Similarly get Employee with max experience in a particular location using predicate, comparator and max.

        System.out.println("----------------Record with Min and Max Value ----------------");
        Comparator<Employee> sortByAge = Comparator.comparing(Employee::getEmpAge);
        List<Employee> arrEmp7 =  arrEmployee.stream()
                                             .min(sortByAge)
                                             .stream()
                                             .collect(Collectors.toList());
        List<Employee> arrEmp8 =  arrEmployee.stream()
                                             .max(sortByAge)
                                             .stream()
                                             .collect(Collectors.toList());
        arrEmp7.forEach(employee -> System.out.println(employee));
        arrEmp8.forEach(employee -> System.out.println(employee));

        System.out.println("----------------Get Employee with Max Exp in Chennai ----------------");
        Predicate<Employee> filterEmpInChennai = employee -> employee.getLocation().equals("Chennai");
        Comparator<Employee> sortByExp = Comparator.comparing(Employee::getTotalExp);
        List<Employee> arrEmp11 =  arrEmployee.stream()
                                              .filter(filterEmpInChennai)
                                              .max(sortByExp)
                                              .stream()
                                              .collect(Collectors.toList());
        arrEmp11.forEach(employee -> System.out.println(employee));

FindFirst Employee who matches criteria and FindAny who matches criteria. Both takes predicate as input.

findAny – Returns an Optional describing some element of the stream, or an empty Optional if the stream is empty.it is free to select any element in the stream. This is to allow for maximal performance in parallel operations;

        System.out.println("----------------Find First  ----------------");
        Predicate<Employee> empStayingInChennai = employee -> employee.getLocation().equals("Chennai");
        List<Employee> arrEmp9 =  arrEmployee.stream()
                                             .filter(empStayingInChennai)
                                             .findFirst()
                                             .stream()
                                             .collect(Collectors.toList());

        arrEmp9.forEach(employee -> System.out.println(employee));

        System.out.println("----------------Find Any  ----------------");
        List<Employee> arrEmp10 =  arrEmployee.stream()
                                              .filter(empAgeGreaterThan30)
                                              .findAny()
                                              .stream()
                                              .collect(Collectors.toList());
        arrEmp10.forEach(employee -> System.out.println(employee));

Get the Sum of salary of Employees in Location(Chennai) using sum

         System.out.println("----------------Sum - Get Sum of Salary in Chennai  ----------------");
        //Method 1
        Integer empTotalSalaryInChennai1 = arrEmployee.stream()
                                                      .filter(empStayingInChennai)
                                                      .map(employee -> employee.getSalary())
                                                      .collect(Collectors.toList())
                                                      .stream()
                                                      .reduce(0, Integer::sum);
        System.out.println("Sum of Empl Salary - Chennai " + empTotalSalaryInChennai1);

        //Method 2
        Integer empTotalSalaryInChennai2 = arrEmployee.stream()
                                                      .filter(empStayingInChennai)
                                                      .mapToInt(Employee::getSalary).sum();
        System.out.println("Sum of Empl Salary - Chennai " + empTotalSalaryInChennai2);

        //Method 3
        Integer empTotalSalaryInChennai3 = arrEmployee.stream() 
                                                      .filter(empStayingInChennai)
                                                      .map(employee -> employee.getSalary())
                                                      .collect(Collectors.summingInt(Integer::intValue));
        System.out.println("Sum of Empl Salary - Chennai " + empTotalSalaryInChennai3);

Get Max and Min salary of employee

  Comparator<Employee> cmpSalComp = (Employee objEmpp1, Employee objEmpp2) -> Double.compare(objEmpp1.Salary,objEmpp2.Salary);

  Employee empMaxObj = arrEmpl.stream()
                                   .max(cmpSalComp)
                                   .get();
                                   
  Employee empMinObj =   arrEmpl.stream()
                                 .min(cmpSalComp)
                                 .get();

Get Average salary of employee grouped by Location

        System.out.println("----------------Average - Grouped by Location  ----------------");
        Map<String, Double> arrAvgSalByLoc =  arrEmpl.stream()
                                                     .collect(Collectors.groupingBy(Employee::getLocation, Collectors.averagingDouble(Employee::getSalary)));
                                         
        System.out.print(arrAvgSalByLoc);

Get Average salary of employee in location using average

        System.out.println("----------------Average - Get Average of Salary in Chennai  ----------------");
        OptionalDouble empAvgSalaryInChennai = arrEmployee.stream()
                                                          .filter(empStayingInChennai)
                                                          .mapToInt(Employee::getSalary)
                                                          .average();
        System.out.println("Average Salary of Employee - Chennai " + empAvgSalaryInChennai);

Get List of Employees in a location using groupingBy. The Return type is hashmap with location as key and List of employees in value

        System.out.println("----------------Group By -  Get Employees grouped by Location  ----------------");
        Map<String, List<Employee>> hmEmp13 = arrEmployee.stream()
                                                         .collect(Collectors.groupingBy(Employee::getLocation));
        hmEmp13.forEach((s, employees) -> {
            System.out.println("Employees from "+ s);
            employees.forEach(employee -> System.out.println(employee));
        });

Get Employee grouped by Location and getting Maximum Salary groupingBy and maxBy

        System.out.println("----------------Group By -  Get Employees with Max Salary in Location  ----------------");
        Comparator<Employee> cmprSalary = Comparator.comparing(Employee::getSalary);
        Map<String, Optional<Employee>> hmEmp14 = arrEmployee.stream()
                                                             .collect(Collectors.groupingBy(Employee::getLocation, Collectors.maxBy(cmprSalary)));

        hmEmp14.forEach((s, employee) -> {
            System.out.print("Employee Location is "+ s +  " and salary is ");
            employee.ifPresent(emp -> System.out.println(emp.getSalary()));
        });

Get Employee Name using mapping grouped by Location using groupingBy

        System.out.println("---------------- Employee at Location -  Using Collectors.mapping  ----------------");
        Map<String, List<String>> hmEmp16 = arrEmployee.stream()
                                                       .collect(Collectors.groupingBy(Employee::getLocation, Collectors.mapping(Employee::getEmpName, Collectors.toList())));

        hmEmp16.forEach((s, employee) -> {
            System.out.println("Employee Name is " + employee + " and Location is "+ s );

        });

Output

true
false
false
----------------Sorted By Name----------------
Employee{empId=106, empName='Dimple', empAge=35, totalExp=5, location='Delhi', pincode='622142', salary=8000}
Employee{empId=103, empName='Madhu', empAge=32, totalExp=6, location='Chennai', pincode='600054', salary=10000}
Employee{empId=102, empName='Mani', empAge=33, totalExp=4, location='Chennai', pincode='600028', salary=6000}
Employee{empId=101, empName='Mugil', empAge=30, totalExp=5, location='Chennai', pincode='600018', salary=5000}
Employee{empId=105, empName='Srini', empAge=40, totalExp=10, location='Delhi', pincode='622142', salary=7000}
Employee{empId=104, empName='Vinu', empAge=29, totalExp=5, location='Bangalore', pincode='500234', salary=15000}
----------------Sorted By Name Reversed----------------
Employee{empId=104, empName='Vinu', empAge=29, totalExp=5, location='Bangalore', pincode='500234', salary=15000}
Employee{empId=105, empName='Srini', empAge=40, totalExp=10, location='Delhi', pincode='622142', salary=7000}
Employee{empId=101, empName='Mugil', empAge=30, totalExp=5, location='Chennai', pincode='600018', salary=5000}
Employee{empId=102, empName='Mani', empAge=33, totalExp=4, location='Chennai', pincode='600028', salary=6000}
Employee{empId=103, empName='Madhu', empAge=32, totalExp=6, location='Chennai', pincode='600054', salary=10000}
Employee{empId=106, empName='Dimple', empAge=35, totalExp=5, location='Delhi', pincode='622142', salary=8000}
----------------Sorted By Name and Age----------------
Employee{empId=106, empName='Dimple', empAge=35, totalExp=5, location='Delhi', pincode='622142', salary=8000}
Employee{empId=103, empName='Madhu', empAge=32, totalExp=6, location='Chennai', pincode='600054', salary=10000}
Employee{empId=102, empName='Mani', empAge=33, totalExp=4, location='Chennai', pincode='600028', salary=6000}
Employee{empId=101, empName='Mugil', empAge=30, totalExp=5, location='Chennai', pincode='600018', salary=5000}
Employee{empId=105, empName='Srini', empAge=40, totalExp=10, location='Delhi', pincode='622142', salary=7000}
Employee{empId=104, empName='Vinu', empAge=29, totalExp=5, location='Bangalore', pincode='500234', salary=15000}
----------------Limit Records to 3 ----------------
Employee{empId=101, empName='Mugil', empAge=30, totalExp=5, location='Chennai', pincode='600018', salary=5000}
Employee{empId=102, empName='Mani', empAge=33, totalExp=4, location='Chennai', pincode='600028', salary=6000}
Employee{empId=103, empName='Madhu', empAge=32, totalExp=6, location='Chennai', pincode='600054', salary=10000}
----------------Skip First 3 Records ----------------
Employee{empId=104, empName='Vinu', empAge=29, totalExp=5, location='Bangalore', pincode='500234', salary=15000}
Employee{empId=105, empName='Srini', empAge=40, totalExp=10, location='Delhi', pincode='622142', salary=7000}
Employee{empId=106, empName='Dimple', empAge=35, totalExp=5, location='Delhi', pincode='622142', salary=8000}
----------------Print Records until Chennai - Keeps printing until condition is True----------------
Employee{empId=101, empName='Mugil', empAge=30, totalExp=5, location='Chennai', pincode='600018', salary=5000}
Employee{empId=102, empName='Mani', empAge=33, totalExp=4, location='Chennai', pincode='600028', salary=6000}
Employee{empId=103, empName='Madhu', empAge=32, totalExp=6, location='Chennai', pincode='600054', salary=10000}
----------------Print Records until Chennai - Stops printing when condition is Met ----------------
Employee{empId=101, empName='Mugil', empAge=30, totalExp=5, location='Chennai', pincode='600018', salary=5000}
Employee{empId=102, empName='Mani', empAge=33, totalExp=4, location='Chennai', pincode='600028', salary=6000}
Employee{empId=103, empName='Madhu', empAge=32, totalExp=6, location='Chennai', pincode='600054', salary=10000}
----------------Record with Min and Max Value ----------------
Employee{empId=104, empName='Vinu', empAge=29, totalExp=5, location='Bangalore', pincode='500234', salary=15000}
Employee{empId=105, empName='Srini', empAge=40, totalExp=10, location='Delhi', pincode='622142', salary=7000}
----------------Get Employee with Max Exp in Chennai ----------------
Employee{empId=103, empName='Madhu', empAge=32, totalExp=6, location='Chennai', pincode='600054', salary=10000}
----------------Find First  ----------------
Employee{empId=101, empName='Mugil', empAge=30, totalExp=5, location='Chennai', pincode='600018', salary=5000}
----------------Find Any  ----------------
Employee{empId=102, empName='Mani', empAge=33, totalExp=4, location='Chennai', pincode='600028', salary=6000}
----------------Sum - Get Sum of Salary in Chennai  ----------------
Sum of Empl Salary - Chennai 21000
Sum of Empl Salary - Chennai 21000
Sum of Empl Salary - Chennai 21000
----------------Average - Get Average of Salary in Chennai  ----------------
Average Salary of Employee - Chennai OptionalDouble[7000.0]
----------------Group By -  Get Employees grouped by Location  ----------------
Employees from Delhi
Employee{empId=105, empName='Srini', empAge=40, totalExp=10, location='Delhi', pincode='622142', salary=7000}
Employee{empId=106, empName='Dimple', empAge=35, totalExp=5, location='Delhi', pincode='622142', salary=8000}
Employees from Chennai
Employee{empId=101, empName='Mugil', empAge=30, totalExp=5, location='Chennai', pincode='600018', salary=5000}
Employee{empId=102, empName='Mani', empAge=33, totalExp=4, location='Chennai', pincode='600028', salary=6000}
Employee{empId=103, empName='Madhu', empAge=32, totalExp=6, location='Chennai', pincode='600054', salary=10000}
Employees from Bangalore
Employee{empId=104, empName='Vinu', empAge=29, totalExp=5, location='Bangalore', pincode='500234', salary=15000}
----------------Group By -  Get Employees with Max Salary in Location  ----------------
Employee Location is Delhi and salary is 8000
Employee Location is Chennai and salary is 10000
Employee Location is Bangalore and salary is 15000
---------------- Employee at Location -  Get Employee Object grouped by Location  ----------------
Employee Location is Delhi
Srini
Dimple
Employee Location is Chennai
Mugil
Mani
Madhu
Employee Location is Bangalore
Vinu
---------------- Employee at Location -  Using Collectors.mapping  ----------------
Employee Name is [Srini, Dimple] and Location is Delhi
Employee Name is [Mugil, Mani, Madhu] and Location is Chennai
Employee Name is [Vinu] and Location is Bangalore

How to find the Stream is Primitive or Wrapper?

public class PrimStreams {
    public static void main(String[] args) {
        List<Integer> arrReviews1 = List.of(8, 9, 8 , 6, 2, 7, 6);
        System.out.println(arrReviews1.stream());

        int[] arrReviews2 = {8, 9, 8 , 6, 2, 7, 6};
        System.out.println(Arrays.stream(arrReviews2));

        System.out.println("----------Wrapper Streams Starts----------");
        System.out.println(arrReviews1.stream().reduce(Integer::sum));
        System.out.println(arrReviews1.stream().reduce(Integer::min));
        System.out.println(arrReviews1.stream().reduce(Integer::max));
        System.out.println(arrReviews1.stream().mapToInt(Integer::intValue).average().orElse(Double.NaN));

        System.out.println("----------Primitive Streams Starts----------");
        System.out.println(Arrays.stream(arrReviews2).sum());
        System.out.println(Arrays.stream(arrReviews2).min());
        System.out.println(Arrays.stream(arrReviews2).max());
        System.out.println(Arrays.stream(arrReviews2).average());
    }
}

In the below output you may see the wrapper class stream would be printed as ReferencePipeline whereas primitive stream would be displayed as IntPipeline. The above code contains doing some basic operation in both primitive and wrapper stream. If the stream is primitive type it would be easy to carry out operation over stream and more memory efficient since there would be no boxing and unboxing involved
Output

java.util.stream.ReferencePipeline$Head@1d251891
java.util.stream.IntPipeline$Head@2133c8f8
----------Wrapper Streams Starts----------
Optional[46]
Optional[2]
Optional[9]
6.571428571428571
----------Primitive Streams Starts----------
46
OptionalInt[2]
OptionalInt[9]
OptionalDouble[6.571428571428571]

How to create a primitive stream of Int?

  IntStream arrReviews3 = IntStream.of(8, 9, 8 , 6, 2, 7, 6);

Basic Operations in primitive stream of Int?

  1. range – Considers nos in specific range.range doesnot takes upper limit no.To address that rangeClosed is used
  2. iterate– Iterate helps in iterating till a particular range by taking Initial and urnaryOperator as params. The default behaviour of Iterator is endless loop.To stop after particular limit like one we did in range we should use limit function.
  3. peek– peek helps going through the values in stream without making any changes. This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline
  4. boxed– boxed will help in boxing primitive to wrapper while collecting the values in to a list.
IntStream arrReviews = IntStream.of(8, 9, 8 , 6, 2, 7, 6);

        System.out.println("----------Stream printing Range of no ----------");

        System.out.println("range doesnot include last no 10 so sum is from 1 to 9 - " + IntStream.range(0,10).sum());
        System.out.println("rangeClosed would include last no 1 to 10 - " + IntStream.rangeClosed(0,10).sum());

        System.out.println("Using Peek we can look at nos in stream");
        System.out.println(IntStream.rangeClosed(0,10)
                                    .peek(System.out::println)
                                    .sum());

        System.out.println("iterate helps in iterating till a specific value");
        System.out.println(IntStream.iterate(1,e->e+1)
                                    .peek(System.out::println)
                                    .limit(10)
                                    .sum());

        System.out.println("iterate helps in iterating till a specific value");
        System.out.println(IntStream.iterate(1,e->e+2)
                                    .peek(System.out::println)
                                    .limit(10)
                                    .sum());

        System.out.println("Iterating over range and collecting in a list");
        List<Integer> arrIntegStream = IntStream.iterate(1,e->e+1)
                                                .peek(System.out::println)
                                                .limit(10)
                                                .boxed()
                                                .collect(Collectors.toList());
        System.out.println(arrIntegStream);

Finding Factorial of No of range 5

public class Factorial {
    public static void main(String[] args) {
        System.out.println(IntStream.rangeClosed(1,5).reduce(1, (x,y)->x*y));

        int i,fact=1;
        int number=5;//It is the number to calculate factorial
        for(i=1;i<=number;i++){
            fact=fact*i;
        }
        System.out.println(fact);
    }
}

Find Maximum of Number in Stream

class HelloWorld {
    public static void main(String[] args) {
       List<Integer> arrNum  = List.of(3,4,5,2,1);
       
       Integer max = arrNum.stream()
                           .max(Integer::compare)
                           .get();
                            
       System.out.print(max);
    }
}

Output

5

The same when used in Objects comparator should be used as one below.

Find Maximum of Number in Stream

.
.       
      Comparator<Employee> sortByExp = Comparator.comparing(Employee::getTotalExp);
      List<Employee> arrEmp11 =  arrEmployee.stream()      
                                            .max(sortByExp);
.
.

Basic String Operation in Streams

  1. Join strings in a list using Collectors.joining
  2. Make Array of String using split. Split would return Array Stream
  3. Apply transformation in elements in list using replaceAll
  4. To flatten the Array Stream in the List use flatMap
  5. Get rid of particular element in List of String using removeIf
  6. Use replaceAll to carry Out Transformation similar to map()
  7. Use peek to support debugging, where you want to see the elements as they flow past a certain point in a pipeline
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StringOps {
    public static void main(String[] args) {
        List<String> arrSkills = List.of("Core Java", "Core Spring", "Spring MVC", "Spring Security", "Spring Boot", "RestAPI");

        System.out.println("-----Join Elements in List using Seperator - [,]---------");
        String skills = arrSkills.stream().collect(Collectors.joining(","));
        System.out.println("Skills are "+ skills);

        System.out.println("-----Split String and Store in String Array---------");
        String[] arrSkillList = skills.split(",");
        Arrays.stream(arrSkillList).forEach(System.out::println);

        System.out.println("-----Convert to UpperCase---------");
        List<String> arrModSkills = new ArrayList(arrSkills);
        arrModSkills.replaceAll(str -> str.toUpperCase());
        arrModSkills.forEach(System.out::println);

        System.out.println("-----Using flatMap to flatten Arrays of Stream and Getting Distinct Location---------");
        List<String> arrLocation = List.of("Madras,Mumbai,Bangalore", "Madras,Kolkatta,Delhi", "Delhi,Madras");
        List allLocations = arrLocation.stream()
                                       .map(location->location.split(","))
                                       .peek(loc-> System.out.println(loc))
                                       .flatMap(Arrays::stream)
                                       .distinct()
                                       .collect(Collectors.toList());

        allLocations.stream()
                    .map(loc->replaceMadras(loc.toString()))
                    .forEach(System.out::println);

        System.out.println("------------Remove Particular Location using removeIf------------");
        allLocations.removeIf(loc->loc.equals("Delhi"));
        allLocations.forEach(loc-> System.out.println(loc));
    }

    private static String replaceMadras(String location){
        if(location.equals("Madras"))
            return "Chennai";
        else
            return location;
    }
}

Converting Multiple List into Single List

public class StreamMisc {
    public static void main(String[] args) {
        List<List<String>> arrSkills = new ArrayList<>();
        arrSkills.add(Arrays.asList("Java", "C++", "C#"));
        arrSkills.add(Arrays.asList("HTML", "CSS"));
        arrSkills.add(Arrays.asList("SQL", "MySQL"));
        arrSkills.add(Arrays.asList("Azure"));

        List<String> arrAllSkills = arrSkills.stream().reduce(new ArrayList<>(), (a, b) -> {
            a.addAll(b);
            return a;
        });

        arrAllSkills.forEach((skill) -> System.out.print(skill + ","));
    }
}

Output

Java,C++,C#,HTML,CSS,SQL,MySQL,Azure

Higher-order functions are functions that take other functions as arguments or return functions as their results.

  1. In the below example we Search employee by Location using Predicate.
  2. If we are not using HOF we need to assign new predicate to variable each and everytime like empFromDelhi
  3. Instead of doing that we have a HOF getEmpByLocation which takes location as string in arguments and returns function in its return type
public class HigherOrdFns {
    public static void main(String[] args) {
        Employee objEmp1 = new Employee(101, "Mugil", 30, "Chennai", "600018", 5, 5000);
        Employee objEmp2 = new Employee(102, "Mani", 33, "Chennai", "600028", 4, 6000);
        Employee objEmp3 = new Employee(103, "Madhu", 32, "Chennai", "600054", 6, 10000);
        Employee objEmp4 = new Employee(104, "Vinu", 29, "Bangalore", "500234", 5, 15000);
        Employee objEmp5 = new Employee(105, "Srini", 40, "Delhi", "622142", 10, 7000);
        Employee objEmp6 = new Employee(106, "Dimple", 35, "Delhi", "622142", 5, 8000);

        List<Employee> arrEmployee = Arrays.asList(objEmp1, objEmp2, objEmp3, objEmp4, objEmp5, objEmp6);

        Predicate<Employee> empFromDelhi = employee -> employee.getLocation().equals("Delhi");

        arrEmployee.stream().filter(empFromDelhi).forEach(System.out::println);
        arrEmployee.stream().filter(getEmpByLocation("Chennai")).forEach(System.out::println);
        arrEmployee.stream().filter(getEmpByLocation("Bangalore")).forEach(System.out::println);
    }

    //Higher Order function which return function as return type
    private static Predicate<Employee> getEmpByLocation(String location) {
        return employee -> employee.getLocation().equals(location);
    }
}

Swagger Consist of Three Parts

  1. swagger-editor– Helps in editing yml file as per Open API Specification
  2. swagger-ui– dist folder helps in circulating API documentation
  3. swagger-codegen

Installing Swagger in Local
Swagger needs http-server. We would use node http-server. We should navigate to the swagger editor folder and start the http-server.

>>npm install -g http-server
>>npm install
>>http-server swagger-editor -a 127.0.0.1 -p 8090
>>http-server swagger-ui -a 127.0.0.1 -p 8091

For the API Documentation we can copy and ship the dist folder in swagger-ui folder. We would have already placed the yaml file which we have created in swagger-editor in swagger-ui folder. Now we should edit the index.html file in swagger-ui folder as below to point to out yml file

index.html

.
.
window.onload = function() {
  // Begin Swagger UI call region
  const ui = SwaggerUIBundle({
  url: "EmpMgmt.yaml",
  dom_id: '#swagger-ui',
   deepLinking: true,
.
.

Presuming the project has Documentation in api-docs folder we can now start the server as below

>>D:\Projects\workspace\EmpMgmt> http-server api-docs -a 127.0.0.1 -p 8091

Refernce for OpenAPI Specification
https://github.com/OAI/OpenAPI-Specification/tree/main/versions

ng serve Loads the project in server
ng test Carries out unit testing.
karma.config.js – defines configuration of test runner
ng lint Checks for violation in coding standard. Checks whether it conforms to standard as defined in tslint.json
ng build creates dist folder in project. dist folder contains js files generated from ts files. The dist folder could be copied and added along with java app and deployed in web server for supporting front end. dist folder is one deployed at end of development I prod
ng e2e much more than unit test. It works by launching angular application in a headless chrome browser. The test are defined in e2e folder
ng new PROJECT_NAME –no-strict creates a new angular project mostly for Development You can toggle by setting strict:false in tsconfig.json
ng new PROJECT_NAME creates a new angular project
ng generate component COMPONENT_NAME generates a new component with component name
ng generate class models/CLASS_NAME generates a class in models folder
ng generate service SERVICE_NAME generates a service
Files and Folders Comments
src->app contains actual project code
dist Contains final distributable js file generated as result of ng build
e2e Contains script for end to end testing
environments Contains the details specific to environment
tsconfig.json code written in ts should be converted to js to get interpretted by browser. This would be configured in tsconfig,json
package.json frameworks and packages needs to execute ng command are defined here
src->main.ts, index.html Responsible for bootstrapping angular application
polyfills.ts take care of browser incompatibility
style.css specifies global application style
test.ts starting point for running unit test
app-routing.module.ts file where all routes are defined
  1. main.ts is starting point of angular application
  2. main.ts refers to app.module.ts which tells the components to be considered during bootstrap
  3. the component by default would be AppComponent which loads the app.component.html
  4. index.html is the root html file which loads the whole app in broswer.When you inspect index.html it would have the same code as one in editor showing loading. The JS files would replace the content in index.html once it gets loaded.Its the same js file which gets generated during ng build placed in dist folder
  5. All components newly added should be registered in app.module.ts. This file is like registry which would help angular to keep track of components
main.ts -> app.module.ts -> Check for bootstrap component

5 ways of passing data between html and components

1 Parent Child @Input
2 Child Parent @Output
3 HTML Form Component Using @Viewchild and ElemRef
4 HTML Form Component @ng-content and @ContentChild
5 HTML Form Component [(ngModel)]

3.@Viewchild and ElemRef
test.component.html

.
.
<input type="text" id="name" class="form-control" #ingName>
.

test.component.ts

export class ShoppingEditComponent implements OnInit 
{
  @ViewChild('ingName') strNameOfIngredient: ElementRef;
  
  ngOnInit(): void 
  {
    console.log(this.strNameOfIngredient.nativeElement.value);
  }
}

Angular Components

  1. Decorators – Passing value between components

    1. Passing Value from Parent to Child – @Input
    2. Passing Value from Child to Parent – @Output
  2. Change Detection
  3. Value Projection

Sending value from Parent to Child Component – Input decorator

  1. There may be times where the value needs to be passed between Parent Component and Child Component
  2. Passing Value occurs by parent HTML app.component.html by defining value to be passed and by using @Input() annotation
  3. In the app.component.ts we are sending a Student object with variable name classRepSent
  4. In the registration.component.ts we are receiving a Student object with variable name classRepReceive
  5. app.component.html is the one which enables passing of variable. The passed variable(classRepSent) is at the right side of bracket “classRepSent” and received variable is on left side in square brackets [classRepReceive]

Sending value from Parent to Child Component
app.component.ts

export class AppComponent {
  public classRepSent:Student; 

  constructor(){
    this.classRepSent= new Student(110, 'Baalaaji', 31, 74, 65,55,64,84); 
  }
  .
  . 
}

registration.component.ts

import { Component, OnInit, Input } from '@angular/core';
.
.
export class RegistrationComponent implements OnInit {
  @Input() public classRepReceive:Student; 
  .
  . 
  ngOnInit() {   
    console.log(this.classRepReceive);                    
  }

app.component.html

<app-registration [classRepReceive]="classRepSent"></app-registration>

Sending value from Child to Parent Component – Output decorator

  1. For Sending value from child component to parent component we use EventEmitter and @Output annotation
  2. We want to send a Student object from Child Component(registration.component.ts) to parent Component(app.component.ts)
  3. Value from child component to parent component could not be sent at time of loading since the components are loaded in hieracial order – parent to child. hence it should be triggered manually in our case we are doing it by using a button
  4. We use a button in registration.component.html which calls a function sendStudent that inturn calls the emitter to send a student with value anand to parent
  5. The Same would be received in app.component.ts using receiveStudent function
  6. Note we are sending a event and receiving a student object. In the HTML we have used receiveStudent as getting event rather than receiving a student object

app.component.ts

export class AppComponent {
.
.
receiveStudent(student:Student){
  console.log(student);
}
.
}

registration.component.ts

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
.
.
export class RegistrationComponent implements OnInit {
  .
  .
  .
  @Output() private student:EventEmitter<Student> = new EventEmitter<Student>();
  .
  .
  sendStudent(pEvent)
  {
    this.student.emit(new Student(106, 'Anandh', 23, 31, 65,55,89,84));
  }
}

app.component.html

<app-registration [classRepReceive]="classRepSent" (student)="receiveStudent($event)"></app-registration>

registration.component.html

.
.
.
<td><input type="button" name="btnCallParent" id="btnCallParent" value="Send Student" (click)="sendStudent($event)"/></td>
.
.
.

Change Detection using ChangeDetection Strategy

  1. Every time angular notices an event it goes through each and every component tree to check the change in the attribute of object. In very large application this could be a bottleneck and going to have a hit on performance.To avoid the unnecessary check on all component we can let angular know the possible components which could be affected during operation.
  2. ChangeDetectionStrateg.default- is the change strategy available to component by default. When a object is created by parent component and shared with child component
    then any change in attribute of object made in parent component would be immediately available to child component and updated in model
  3. ChangeDetectionStrateg.OnPush – is forcing angular to refresh view of child only when the object is accessed.(Note:This object is created in Parent). Though the child component
    would have the updated value it wont be shown up in view.

  1. The object which is created in parent is shared in between parent and child.
  2. In the above Screen the Counter as in Parent and Counter as in Child would have the same value irrespective of whether you click increment from parent or increment from childwhen the ChangeDetection Strategy is set to default.When the ChangeDetection Strategy is set to default then incrementing counter using Increment Counter From Parent and Increment Counter From child would have the same effect.
  3. The Counter as in Parent and Counter as in Child would be changed immediately and reflected in screen. This is nature of angular to detect refresh all component when attribute of object used in one component is changed.But in big application many component need not be refreshed and we could tell angular what component needs to be checked
  4. When the ChangeDetection Strategy is set to onPush in child then the incrementing the parent counter wont be reflected in Counter as in Child.The updated value would be shown in child only when object is accessed by child component. Otherwise, increment counter in child would display updated value in Counter as in Child

ParentcounterComponent.ts

import { Component, OnInit } from '@angular/core';
import { Counter } from 'src/app/model/counter';

@Component({
  selector: 'app-parentcounter',
  templateUrl: './parentcounter.component.html',
  styleUrls: ['./parentcounter.component.css']
})
export class ParentcounterComponent implements OnInit {

  constructor() { }

  public counter : Counter;

  ngOnInit(): void {
    this.counter = new Counter(1);
  }


  increaseCounter()
  {        
    this.counter.value +=2;
    console.log(this.counter.value);
  }

  createNewCounter(){
    this.counter = new Counter(1);
  }
}

CounterComponent.ts

import { Component, OnInit, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
import { Counter } from 'src/app/model/counter';

@Component({
  selector: 'app-counter',
  templateUrl: './counter.component.html',
  styleUrls: ['./counter.component.css']
})
export class CounterComponent implements OnInit {

  @Input() public counterVal: Counter;
  @Output() private counterEmitter: EventEmitter<Counter>;   

  ngOnInit(): void {    
  }

  increaseChildCounter()
  {
    console.log(this.counterVal.value);
    this.counterVal.value +=1;
  }

  sendCounterToParentComp(){     
    this.counterEmitter.emit(this.counterVal);
  }
}

parentcounter.component.html

<span>Counter as in Parent - {{counter.value}}</span><br/>    <br/>    
<app-counter [counterVal]="counter"></app-counter><br/>    
<button (click)="increaseCounter()">Increment Counter From Parent</button><br/> <br/>       
<button (click)="createNewCounter()">Create New Counter Object </button><br/>  <br/>     

counter.component.html

<span>Counter as in Child - {{counterVal.value}}</span><br/>    <br/>    
<button (click)="increaseChildCounter()">Update Counter From Child</button><br/>