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.

        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 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

Streams

  1. Intermediate Operations returns Stream as output. methods like map(), sorted(), distinct() would return stream as output
  2. Terminal Operations returns something other than Stream. Collect() returns collection. Reduce() returns one element

Converting list to a stream

List<Integer> arrNumbers = List.of(10,27,31, 35, 40, 44, 48, 50);
//Convert list to stream
Stream objStream = arrNumbers.stream();

//Static Method Reference
objStream.forEach(System.out::println);

Filter

  1. Filter takes a predicate as argument. Predicate returns boolean. The Output of Filter is a Stream
  2. Predicate object which is technically a function to convert an object to boolean. We pass an object and it will return true or false.
  3. filter() method is lazy like map, it wont be evaluated until you call a reduction method, like collect
List<Integer> arrNumbers = List.of(10,27,31, 35, 40, 44, 48, 50);
List<String> arrSkills = List.of("Spring Boot", "Spring Security", "Java 8", "Microservices", "Spring MVC");

//Printing Even Numbers
System.out.println("------Even Numbers-------");
arrNumbers.stream().filter(FilterEgs::isEven).forEach(System.out::println);

//Printing Even Numbers
System.out.println("------Even Numbers-------");
arrNumbers.stream().filter(no -> no%2==0).forEach(System.out::println);

//Printing Odd Numbers
System.out.println("------Odd Numbers-------");
arrNumbers.stream().filter(no -> no%2==1).forEach(System.out::println);

//Printing Odd Numbers
System.out.println("------Print Spring Skills-------");
arrSkills.stream().filter(skill -> skill.toLowerCase().contains("spring"))
.forEach(System.out::println);

private static boolean isEven(int no){
        return no%2==0;
}       

Output

------Even Numbers-------
10
40
44
48
50
------Odd Numbers-------
27
31
35
------Print Spring  Skills-------
Spring Boot
Spring Security
Spring MVC

Map

  1. Map takes a function as a argument and performs transform action on elements. The Output of Map is a Stream
  2. map() is used to transform one object into another by applying a function.
  3. Stream.map(Function mapper) takes a function as an argument.
  4. mapping function converts one object to the other. Then, the map() function will do the transformation for you. It is also an intermediate Stream operation, which means you can call other Stream methods, like a filter, or collect on this to create a chain of transformations.
List<Integer> arrNumbers = List.of(10,27,31, 35, 40, 44, 48, 50);
List<String> arrSkills = List.of("Spring Boot", "Spring Security", "Java 8", "Microservices", "Spring MVC");

//Printing Square of Numbers
System.out.println("------Square of Numbers-------");
arrNumbers.stream()
		.filter(no -> no%2==0)
		.map(no -> no*no)
		.forEach(System.out::println);

//Print Total Characters in String
System.out.println("------Print Total Characters in String-------");
arrSkills.stream()
		.map(skill -> skill + " contains "+ skill.length()+ " Characters")
		.forEach(System.out::println);

Reduce

  1. Stream.reduce() takes function as Parameter
  2. Reduction stream operations allow us to produce one single result from a sequence of elements, by repeatedly applying a combining operation to the elements in the sequence.
  3. Stream.reduce() operation Contains Identity, Accumulator and Combiner
  4. Identity – an element that is the initial value of the reduction operation and the default result if the stream is empty
  5. Accumulator – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream
  6. Combiner – a function used to combine the partial result of the reduction operation when the reduction is parallelized or when there’s a mismatch between the types of the accumulator arguments and the types of the accumulator implementation

ReduceEgs.java

import java.util.Arrays;
import java.util.List;

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

        System.out.println(arrNumbers.stream().reduce(0, ReduceEgs::sumNos));
    }

    public static Integer sumNos(int x, int y){
        System.out.println("a -"+ x + " b - "+  y);

        return x+y;
    }
}

Output

a -0 b - 1
a -1 b - 2
a -3 b - 3
a -6 b - 4
a -10 b - 5
a -15 b - 6
a -21 b - 7
a -28 b - 8
a -36 b - 9
45

In the above example

  1. the Integer value 0 is the identity. It stores the initial value of the reduction operation and also the default result when the stream of Integer values is empty.
  2. the lambda expression x+y represented by function sumNos is the accumulator since it takes the partial sum of Integer values and the next element in the stream.
  3. When a stream executes in parallel, the Java runtime splits the stream into multiple substreams. In such cases, we need to use a function to combine the results of the substreams into a single one. This is the role of the combiner

Role of combiner would be visibile only in parallelStream with output as below. It would be hard to interpret the output response in console.

ReduceEgs.java

.
.
 System.out.println(arrNumbers.parallelStream().reduce(0, ReduceEgs::sumNos));
.
.

Output

a -0 b - 6
a -0 b - 5
a -5 b - 6
a -0 b - 1
a -0 b - 7
a -0 b - 9
a -0 b - 2
a -1 b - 2
a -0 b - 3
a -0 b - 8
a -8 b - 9
a -0 b - 4
a -3 b - 4
a -3 b - 7
a -7 b - 17
a -11 b - 24
a -10 b - 35
45

Alternate ways to Sum Nos

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);

 System.out.println(sum);
 System.out.println(sum2);
}

How to Search for Product with least cost from List? I have a List of Speakers in List. I want to get the speaker with the least cost.

Speakers.java

package com.mugil.bean;

public class Speakers {
 private Integer speakerID;
 private String companyName;
 private Integer price;
 private String sellerName;

 public Speakers(Integer pSpeakerId, String pcompanyName, Integer pPrice, String psellerName) {
  this.speakerID = pSpeakerId;
  this.companyName = pcompanyName;
  this.price = pPrice;
  this.sellerName = psellerName;
 }

 public int getSpeakerID() {
  return speakerID;
 }
 public void setSpeakerID(int speakerID) {
  this.speakerID = speakerID;
 }
 public String getCompanyName() {
  return companyName;
 }
 public void setCompanyName(String companyName) {
  this.companyName = companyName;
 }
 public int getPrice() {
  return price;
 }
 public void setPrice(int price) {
  this.price = price;
 }

 public String getSellerName() {
  return sellerName;
 }

 public void setSellerName(String sellerName) {
  this.sellerName = sellerName;
 }

 @Override
 public String toString() {
  return "Speakers [speakerID=" + speakerID + ", companyName=" + companyName + ", price=" + price +
   ", sellerName=" + sellerName + "]";
 }
}

SearchSpeakers.java

package com.mugil.test;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import com.mugil.bean.Speakers;

public class SearchSpeakers {

 public static void main(String[] args) {
  Speakers objSpeaker1 = new Speakers(101, "JBL Go", 120, "Amazon");
  Speakers objSpeaker2 = new Speakers(102, "Panasonic", 420, "Amazon");
  Speakers objSpeaker3 = new Speakers(103, "JBL Go", 900, "Flipkart");
  Speakers objSpeaker4 = new Speakers(104, "JBL Go", 120, "Amazon");
  Speakers objSpeaker5 = new Speakers(105, "JBL Go", 350, "Amazon");
  Speakers objSpeaker6 = new Speakers(101, "Philips", 120, "EBay");
  Speakers objSpeaker7 = new Speakers(102, "JBL Go", 125, "Ebay");
  Speakers objSpeaker8 = new Speakers(103, "JBL Go", 35, "Smart Shoppe");
  Speakers objSpeaker9 = new Speakers(104, "Panasonic", 80, "Amazon");
  Speakers objSpeaker10 = new Speakers(105, "Philips", 180, "Amazon");

  List < Speakers > arrSpeakers = new ArrayList < Speakers > ();

  arrSpeakers.add(objSpeaker1);
  arrSpeakers.add(objSpeaker2);
  arrSpeakers.add(objSpeaker3);
  arrSpeakers.add(objSpeaker4);
  arrSpeakers.add(objSpeaker5);
  arrSpeakers.add(objSpeaker6);
  arrSpeakers.add(objSpeaker7);
  arrSpeakers.add(objSpeaker8);
  arrSpeakers.add(objSpeaker9);
  arrSpeakers.add(objSpeaker10);

  Comparator < Speakers > spkComparator = (Speakers objSpeaker1a, Speakers objSpeaker2a) -> objSpeaker1a.getPrice() - objSpeaker2a.getPrice();

  arrSpeakers.stream().sorted(spkComparator).collect(Collectors.groupingBy(Speakers::getCompanyName)).values()
   .stream().forEach(searchedModel -> System.out
    .println("Speaker with Lowest Cost" + searchedModel.stream().findFirst()));
 }
}
arrSpeakers.stream().sorted(spkComparator).collect(Collectors.groupingBy(Speakers::getCompanyName)).values()
   .stream().forEach(searchedModel -> System.out
    .println("Speaker with Lowest Cost" + searchedModel.stream().findFirst()));

arrSpeakers.stream() – Convert to Stream
arrSpeakers.stream().sorted(spkComparator) – Sorts the list by price
arrSpeakers.stream().sorted(spkComparator).collect(Collectors.groupingBy(Speakers::getCompanyName)) – Groups the Sorted List by Company Name
arrSpeakers.stream().sorted(spkComparator).collect(Collectors.groupingBy(Speakers::getCompanyName)).values()
.stream()
– Convert the Sorted List into Stream

Output

Speaker with Lowest CostOptional[Speakers [speakerID=101, companyName=Philips, price=120, sellerName=EBay]]
Speaker with Lowest CostOptional[Speakers [speakerID=104, companyName=Panasonic, price=80, sellerName=Amazon]]
Speaker with Lowest CostOptional[Speakers [speakerID=103, companyName=JBL Go, price=35, sellerName=Smart Shoppe]]