Understanding Java 8 Streams and working with collections using Lambda expressions
Assumes that you have read and understand Java 8 Lambda Expressions and functional interface tutorials
A stream is an infinite sequence of consumable elements (i.e a data structure) for the consumption of an operation or iteration. Any Collection can be exposed as a stream. The operations you perform on a stream can either be
- intermediate (map, filter, sorted, limit, skip,concat, substream, distinct, etc) producing another stream or
- terminal (forEach, reduce, collect, sum, max, count, matchAny, findFirst, findAny, etc) producing an object that is not a stream.
ls -l | grep "Dec" | Sort +4n | more
stream( ) is a default method added to the Collection interface in Java 8. The stream( ) returns a java.util.Stream interface with multiple abstract methods like filter, map, sorted, collect, etc. DelegatingStream is implements these abstract methods.
Java 8 Example 1:
package com.java8.examples;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class EmployeeTest {
private static List<Employee> employees = Arrays.asList(
new Employee("Steve", BigDecimal.valueOf(35000), Employee.WorkType.PARTTIME),
new Employee("Peter", BigDecimal.valueOf(65000), Employee.WorkType.FULLTIME),
new Employee("Sam", BigDecimal.valueOf(75000), Employee.WorkType.FULLTIME),
new Employee("John", BigDecimal.valueOf(25000), Employee.WorkType.CASUAL));
public static void main(String[] args) {
//e is the parameter for Employee
List<Employee> fullTimeEmployees = employees.stream() //returns a stream (intermediate)
.filter(e -> e.getWorkType() == Employee.WorkType.FULLTIME)//returns a stream (intermediate)
.collect(Collectors.toList()); // returns a list (terminal)
fullTimeEmployees.forEach(e -> System.out.println(e)); //Peter & Sam
}
}
The output is:
Employee [name=Peter, salary=65000, workType=FULLTIME]
Employee [name=Sam, salary=75000, workType=FULLTIME]
The above example creates a new list of full time employees. The operations .stream( ), .filter( ) create the intermediate streams, hence they are chained, and the .collect is the terminal operation that returns the final List of full-time employees.
This is enabled in the Iterable interface, which is a functional interface with the forEach default method. A List and other collections implements the Iterable functional interface to allow lambda expressions.
The Employee class will look like
package com.java8.examples;
import java.math.BigDecimal;
public class Employee {
public enum WorkType {FULLTIME, PARTTIME, CASUAL}
private String name;
private BigDecimal salary;
private WorkType workType;
public Employee(String name, BigDecimal salary, WorkType workType) {
super();
this.name = name;
this.salary = salary;
this.workType = workType;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getSalary() {
return salary;
}
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
public WorkType getWorkType() {
return workType;
}
public void setWorkType(WorkType workType) {
this.workType = workType;
}
@Override
public String toString() {
return "Employee [name=" + name + ", salary=" + salary + ", workType=" + workType + "]";
}
}
Java 8 Example 2:
Now, in the same example, if you want to print all the employees who earn more than 25,000, sorted by WorkType, in the format "<name> earns <salary> on a <work type> basis.
//e is the parameter for Employee employees.stream() //returns a stream (intermediate) .filter(e -> e.getSalary().doubleValue() > 25000) // returns a stream (intermediate) .sorted((e1,e2) -> e1.getWorkType().compareTo(e2.getWorkType())) .map(e -> e.getName() + " earns " + e.getSalary() + " on a " + e.getWorkType() + " basis") .forEach(System.out::println); //terminal
Isn't this cool? This is like writing the SQL where clause.
Output:
Peter earns 65000 on a FULLTIME basis
Sam earns 75000 on a FULLTIME basis
Steve earns 35000 on a PARTTIME basis
Java 8 Example 3:
Get a comma separated string of all employees earning more than 25,000.00 as salary.
//e is the parameter for Employee
String str = employees.stream() //returns a stream (intermediate)
.filter(e -> e.getSalary().doubleValue() > 25000) // returns a stream (intermediate)
.map(e -> e.getName())// returns a stream (intermediate)
.distinct() //returns a stream (intermediate)
//terminal returning a string
.reduce("Distinct first names earning > 25000:", (name1, name2) -> name1+ "," + name2 );
System.out.println("CSV: " + str);
Output:
CSV: Distinct first names earning > 25000:,Steve,Peter,Sam
Java 8 Example 4:
Aggregate the salary by WorkType.
//e is the parameter for Employee
employees.stream() //returns a stream (intermediate)
.collect(Collectors.groupingBy(Employee::getWorkType))
.forEach((gr,le) -> {System.out.println(" Aggregated Salary for " + gr + " is " +
+ le.stream().mapToDouble(e -> e.getSalary().doubleValue()).sum());
});
Output:
Aggregated Salary for CASUAL is 25000.0
Aggregated Salary for FULLTIME is 140000.0
Aggregated Salary for PARTTIME is 35000.0
Java 8 Example 5:
Get the employee who earns the highest salary.
//e is the parameter for Employee
Employee maxSalaryEmployee = employees.stream() //returns a stream (intermediate)
.max((e1, e2) -> (e1.getSalary().compareTo(e2.getSalary())))
.get();
System.out.println(maxSalaryEmployee);
Output:
Employee [name=Sam, salary=75000, workType=FULLTIME]
Labels: Java 8

0 Comments:
Post a Comment
Subscribe to Post Comments [Atom]
<< Home