Saturday 15 August 2015

Java8: Stream operations

‘java.util.stream.Stream’ class define number of operations, which are grouped into two categories.

a.   Pipeline operations like map, limit, filter etc., these are called intermediate operations.
b.   Collect the result and close the stream. These are called terminal operations.

Pipeline Operations
Lets talk about pipeline operations here. All pipeline operations like map, filter return other stream as output.

Following table illustrates pipeline operations.
Method
Return type
Argument
Description
filter
Stream
Predicate
Returns  stream of elements that matches given predicate.
map
Stream
Function
Returns a stream consisting of the results of applying the given function to the elements of this stream.
limit
Stream
long
Returns a stream
sorted
Stream
Comparator
Returns a stream consisting of the elements of this stream, sorted according to the provided Comparator.
distinct
Stream
No arguments
Returns a stream consisting of the distinct elements according to equlas method of this stream.
flatMap
Stream
Function
Returns a stream consisting of the results of replacing each element of  this stream with the contents of a mapped stream produced by applying the provided mapping function to each element.
peek
Stream
Consumer
Returns a stream consisting of the elements of this stream by performing the provided action on each element.
skip
Stream
long
Returns a stream by skipping first n elements.


Termial Operations
Method
Return type
Argument
Description
forEach
void
Consumer
Performs action on each element of this stream.
count
long
void
Returns number of elements in this stream
collect
Type of the reduction
Collector (or) (Supplier, BitConsumer, BitConsumer)
Perform reduction operation on given stream of elements.

Better way to understand stream is to write programs using streams. Following examples use Employee class with properties id, firstName, lastName, age, city, salary. At the end of this post, you can see full application.

1. Get all employee who are staying at Chennai
employees.stream().filter((emp) -> emp.getCity().equals("Chennai")).collect(Collectors.toList());

I used filter operation, which takes as preadicate ‘(emp) -> emp.getCity().equals("Chennai")’ and returns a stream which include all elements that match predicate.

2. Get all employees whose salary > 100000.
employees.stream().filter((emp) -> emp.getSalary() > 100000).collect(Collectors.toList());

Above method returns following output.

[PTR(Hyderabad,27,123456.000000), Raju(Trivendram,40,198765.000000), Raju(Trivendram,40,198765.000000)]

As you onserve employee ‘Raju(Trivendram,40,198765.000000)’ is duplicated (repeated twice). If you want to get distinct elements use distinct method. Next example explain this.

3. Get all distinct employees whose salary > 100000.
employees.stream().filter((emp) -> emp.getSalary() > 100000).distinct().collect(Collectors.toList());

4. Get first 3 employees whose salary is > 50000.
You can use limit method to limit number of results.

employees.stream().filter((emp) -> emp.getSalary() > 50000).distinct().limit(3).collect(Collectors.toList());

5. Sort employees by salary, whose salary is > 80000.
employees.stream().filter((emp) -> emp.getSalary() > 80000).distinct().sorted(comparing(Employee::getSalary)).collect(Collectors.toList());

Above query returns following results.

[Sudheer(Bangalore,27,90000.000000), Siva krishna(Hyderabad,28,98765.000000), Brijesh(Trivendram,34,100000.000000), PTR(Hyderabad,27,123456.000000), Raju(Trivendram,40,198765.000000)]

6. Sort employees by salary, whose salary is > 80000, and skip first 3 employees.
Streams support skip method, skip(n) skips n number of objects in the stream.

employees.stream().filter((emp) -> emp.getSalary() > 80000).distinct().sorted(comparing(Employee::getSalary)).skip(3).collect(Collectors.toList());

Above query returns following result.

[PTR(Hyderabad,27,123456.000000), Raju(Trivendram,40,198765.000000)]

Select particular properties of object.
In SQL, you can select particular columns using SELECT query. Same functionality you can achieve using map, flatmap method of stream class.

7. Get all firstNames from all employees.

employees.stream().map(Employee::getFirstName).collect(Collectors.toList());

8. Get id, Employee from all employees.
employees.stream().distinct().collect(Collectors.toMap(Employee::getId, employee -> employee));

9. Get id, firstName from all employees.
employees.stream().distinct().collect(Collectors.toMap(Employee::getId, Employee::getFirstName));

10. Get length of all employee first names.

employees.stream().map(Employee::getFirstName).map(String::length).collect(Collectors.toList())

I hope with these examples you got some basic idea on using stream. Following is the complete application for above examples.
import java.util.Objects;

public class Employee {
 private int id;
 private String firstName;
 private String lastName;
 private int age;
 private String city;
 private double salary;

 public Employee(int id, String firstName, String lastName, int age,
   String city, double salary) {
  super();
  this.id = id;
  this.firstName = firstName;
  this.lastName = lastName;
  this.age = age;
  this.city = city;
  this.salary = salary;
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

 public int getAge() {
  return age;
 }

 public void setAge(int age) {
  this.age = age;
 }

 public String getCity() {
  return city;
 }

 public void setCity(String city) {
  this.city = city;
 }

 public double getSalary() {
  return salary;
 }

 public void setSalary(double salary) {
  this.salary = salary;
 }

 @Override
 public boolean equals(Object employee) {
  if (Objects.isNull(employee))
   return false;

  if (!(employee instanceof Employee))
   return false;

  Employee emp = (Employee) employee;

  return id == emp.id;
 }

 @Override
 public int hashCode() {
  return Objects.hash(id, firstName, lastName, age);
 }

 @Override
 public String toString() {
  return String.format("%s(%s,%d,%f)", firstName, city, age, salary);
 }

}

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import java.util.Map;
import static java.util.Comparator.comparing;

public class EmployeeTest {

 public static <T> List<T> processEmployees(List<T> employees,
   Predicate<T> predicate) {
  List<T> tmpList = new ArrayList<>();
  for (T emp : employees) {
   if (predicate.test(emp)) {
    tmpList.add(emp);
   }
  }
  return tmpList;
 }

 public static List<Employee> getEmployees() {
  Employee emp1 = new Employee(1, "Hari Krishna", "Gurram", 26,
    "Bangalore", 40000);
  Employee emp2 = new Employee(2, "Joel", "Chelli", 27, "Hyderabad",
    50000);
  Employee emp3 = new Employee(3, "Shanmukh", "Kummary", 28, "Chennai",
    35000);
  Employee emp4 = new Employee(4, "Harika", "Raghuram", 27, "Chennai",
    76000);
  Employee emp5 = new Employee(5, "Sudheer", "Ganji", 27, "Bangalore",
    90000);
  Employee emp6 = new Employee(6, "Rama Krishna", "Gurram", 27,
    "Bangalore", 56700);
  Employee emp7 = new Employee(7, "PTR", "PTR", 27, "Hyderabad", 123456);
  Employee emp8 = new Employee(8, "Siva krishna", "Ponnam", 28,
    "Hyderabad", 98765);
  Employee emp9 = new Employee(9, "Raju", "Antony", 40, "Trivendram",
    198765);

  Employee emp10 = new Employee(10, "Brijesh", "Krishnan", 34,
    "Trivendram", 100000);
  Employee emp11 = new Employee(9, "Raju", "Antony", 40, "Trivendram",
    198765);

  Employee emp12 = new Employee(10, "Brijesh", "Krishnan", 34,
    "Trivendram", 100000);

  List<Employee> employees = new ArrayList<>();

  employees.add(emp1);
  employees.add(emp2);
  employees.add(emp3);
  employees.add(emp4);
  employees.add(emp5);
  employees.add(emp6);
  employees.add(emp7);
  employees.add(emp8);
  employees.add(emp9);
  employees.add(emp10);
  employees.add(emp11);
  employees.add(emp12);

  return employees;
 }

 public static void main(String args[]) {
  List<Employee> employees = getEmployees();
  List<Employee> temp;

  /* Get all employees staying at Chennai */
  temp = employees.stream()
    .filter((emp) -> emp.getCity().equals("Chennai"))
    .collect(Collectors.toList());
  System.out.println(temp + "\n");

  /* Get all employees whose salary > 100000 */
  temp = employees.stream().filter((emp) -> emp.getSalary() > 100000)
    .collect(Collectors.toList());
  System.out.println(temp + "\n");

  /* Get all employees whose salary > 100000 */
  temp = employees.stream().filter((emp) -> emp.getSalary() > 100000)
    .distinct().collect(Collectors.toList());
  System.out.println(temp + "\n");

  /* Get first 3 employees whose salary is > 50000 */
  temp = employees.stream().filter((emp) -> emp.getSalary() > 50000)
    .distinct().limit(3).collect(Collectors.toList());
  System.out.println(temp + "\n");

  /* Sort employees by salary, whose salary is > 80000 */
  temp = employees.stream().filter((emp) -> emp.getSalary() > 80000)
    .distinct().sorted(comparing(Employee::getSalary))
    .collect(Collectors.toList());
  System.out.println(temp + "\n");

  /*
   * Sort employees by salary, whose salary is > 80000, and skip first 3
   * employees.
   */
  temp = employees.stream().filter((emp) -> emp.getSalary() > 80000)
    .distinct().sorted(comparing(Employee::getSalary)).skip(3)
    .collect(Collectors.toList());
  System.out.println(temp + "\n");

  /* Get all firstNames from all employees. */
  List<String> firstNames = employees.stream()
    .map(Employee::getFirstName).collect(Collectors.toList());
  System.out.println(firstNames + "\n");

  /* Get id, Employee from all employees. */
  Map<Integer, Employee> map = employees
    .stream()
    .distinct()
    .collect(
      Collectors.toMap(Employee::getId, employee -> employee));
  System.out.println(map + "\n");

  /* Get id, firstName from all employees. */
  Map<Integer, String> map1 = employees
    .stream()
    .distinct()
    .collect(
      Collectors.toMap(Employee::getId,
        Employee::getFirstName));
  System.out.println(map1 + "\n");

  /* Get length of all employee first names */
  List<Integer> lengths = employees.stream().map(Employee::getFirstName)
    .map(String::length).collect(Collectors.toList());
  System.out.println(lengths + "\n");

 }
}


Output
[Shanmukh(Chennai,28,35000.000000), Harika(Chennai,27,76000.000000)]

[PTR(Hyderabad,27,123456.000000), Raju(Trivendram,40,198765.000000), Raju(Trivendram,40,198765.000000)]

[PTR(Hyderabad,27,123456.000000), Raju(Trivendram,40,198765.000000)]

[Harika(Chennai,27,76000.000000), Sudheer(Bangalore,27,90000.000000), Rama Krishna(Bangalore,27,56700.000000)]

[Sudheer(Bangalore,27,90000.000000), Siva krishna(Hyderabad,28,98765.000000), Brijesh(Trivendram,34,100000.000000), PTR(Hyderabad,27,123456.000000), Raju(Trivendram,40,198765.000000)]

[PTR(Hyderabad,27,123456.000000), Raju(Trivendram,40,198765.000000)]

[Hari Krishna, Joel, Shanmukh, Harika, Sudheer, Rama Krishna, PTR, Siva krishna, Raju, Brijesh, Raju, Brijesh]

{1=Hari Krishna(Bangalore,26,40000.000000), 2=Joel(Hyderabad,27,50000.000000), 3=Shanmukh(Chennai,28,35000.000000), 4=Harika(Chennai,27,76000.000000), 5=Sudheer(Bangalore,27,90000.000000), 6=Rama Krishna(Bangalore,27,56700.000000), 7=PTR(Hyderabad,27,123456.000000), 8=Siva krishna(Hyderabad,28,98765.000000), 9=Raju(Trivendram,40,198765.000000), 10=Brijesh(Trivendram,34,100000.000000)}

{1=Hari Krishna, 2=Joel, 3=Shanmukh, 4=Harika, 5=Sudheer, 6=Rama Krishna, 7=PTR, 8=Siva krishna, 9=Raju, 10=Brijesh}

[12, 4, 8, 6, 7, 12, 3, 12, 4, 7, 4, 7]




Prevoius                                                 Next                                                 Home

No comments:

Post a Comment