Article directory:
2.1 finding and matching of termination operation
2.2 reduction and collection of termination operation
1. Write in front
Following the previous article (having finished the creation method and intermediate operation of Stream API): Creation method and intermediate operation of Stream API.
We all know that the operation completed by the Stream API requires three steps: create Stream → intermediate operation → terminate operation. In this article, let's talk about termination.
2. Terminate the operation
The terminal operation generates results from the pipeline of the stream. The result can be any value that is not a stream, such as List, Integer, or even void.
2.1 finding and matching of termination operation
First, we still need a custom Employee class and a List collection to store it.
Enumeration is defined in the Employee class (BUSY: BUSY; FREE: FREE; VOCATION: vacation)
package com.szh.java8; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * */ @Data @NoArgsConstructor @AllArgsConstructor public class Employee2 { private Integer id; private String name; private Integer age; private Double salary; private Status status; public Employee2(Integer id) { this.id = id; } public Employee2(Integer id, String name) { this.id = id; this.name = name; } public enum Status { FREE, BUSY, VOCATION } }
List<Employee2> employees = Arrays.asList( new Employee2(1001,"Zhang San",26,6666.66, Employee2.Status.BUSY), new Employee2(1002,"Li Si",50,1111.11,Employee2.Status.FREE), new Employee2(1003,"Wang Wu",18,9999.99,Employee2.Status.VOCATION), new Employee2(1004,"Zhao Liu",35,8888.88,Employee2.Status.BUSY), new Employee2(1005,"Tian Qiyi",44,3333.33,Employee2.Status.FREE), new Employee2(1005,"Tian Qier",44,3333.33,Employee2.Status.VOCATION), new Employee2(1005,"Panax notoginseng",44,3333.33,Employee2.Status.BUSY) );
Check whether all employees are in BUSY status, at least one employee is in FREE status and no employee is in VOCATION status.
@Test public void test1() { boolean b1 = employees.stream() .allMatch((e) -> e.getStatus().equals(Employee2.Status.BUSY)); System.out.println(b1); boolean b2 = employees.stream() .anyMatch((e) -> e.getStatus().equals(Employee2.Status.FREE)); System.out.println(b2); boolean b3 = employees.stream() .noneMatch((e) -> e.getStatus().equals(Employee2.Status.VOCATION)); System.out.println(b3); }
After sorting employee salary, return the information of the first employee; After filtering out employees in BUSY status, the information of any employee in BUSY status is returned.
@Test public void test2() { Optional<Employee2> op1 = employees.stream() .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())) .findFirst(); System.out.println(op1.get()); System.out.println("----------------------------------"); Optional<Employee2> op2 = employees.stream() .filter((e) -> e.getStatus().equals(Employee2.Status.BUSY)) .findAny(); System.out.println(op2.get()); }
Next, let's look at another set of methods to find and match.
Calculate the number of employees in VOCATION status; Map the employee salary field and obtain the highest salary; Get the information of the youngest employee.
@Test public void test3() { long count = employees.stream() .filter((e) -> e.getStatus().equals(Employee2.Status.VOCATION)) .count(); System.out.println(count); Optional<Double> op1 = employees.stream() .map(Employee2::getSalary) .max(Double::compare); System.out.println(op1.get()); Optional<Employee2> op2 = employees.stream() .min((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())); System.out.println(op2.get()); }
Here, you should pay attention to one thing: once the current Stream is terminated, it cannot be used again.
Let's look at the following code case. (the exception message says that the stream has been closed)
@Test public void test4() { Stream<Employee2> stream = employees.stream() .filter((e) -> e.getStatus().equals(Employee2.Status.BUSY)); long count = stream.count(); stream.map(Employee2::getName); }
2.2 reduction and collection of termination operation
The implementation of the method in the Collector interface determines how to perform collection operations (such as collecting List, Set and Map). However, the Collectors utility class provides many static methods to easily create common Collector instances. The specific methods and instances are shown in the following table:
Calculate the sum of integers 1 ~ 10; After mapping the employee salary field, get the total salary of all employees.
@Test public void test1() { List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10); Integer sum = list.stream() .reduce(0, (x, y) -> x + y); System.out.println(sum); System.out.println("-------------------------------"); Optional<Double> optional = employees.stream() .map(Employee2::getSalary) .reduce(Double::sum); System.out.println(optional.get()); }
Map the name field of the previously defined List Set for storing employee information, and then convert it to List, Set and HashSet (using Static methods in the Collectors utility class).
In the Set and HashSet sets, there is only one tianqier because the elements are disordered and non repeatable.
@Test public void test2() { List<String> list = employees.stream() .map(Employee2::getName) .collect(Collectors.toList()); list.forEach(System.out::println); System.out.println("-------------------------------"); Set<String> set = employees.stream() .map(Employee2::getName) .collect(Collectors.toSet()); set.forEach(System.out::println); System.out.println("-------------------------------"); HashSet<String> hashSet = employees.stream() .map(Employee2::getName) .collect(Collectors.toCollection(HashSet::new)); hashSet.forEach(System.out::println); }
Map the employee salary field, and then obtain the highest salary through the comparator;
Without mapping, the information of the employee with the lowest salary is obtained directly through the comparator;
Calculate the total salary of all employees;
Calculate the average salary of all employees;
Calculate the total number of employees;
Map the employee salary field, and then obtain the highest salary through the comparator;
@Test public void test3() { Optional<Double> max = employees.stream() .map(Employee2::getSalary) .collect(Collectors.maxBy(Double::compare)); System.out.println(max.get()); Optional<Employee2> min = employees.stream() .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))); System.out.println(min.get()); Double sum = employees.stream() .collect(Collectors.summingDouble(Employee2::getSalary)); System.out.println(sum); Double avg = employees.stream() .collect(Collectors.averagingDouble(Employee2::getSalary)); System.out.println(avg); Long count = employees.stream() .collect(Collectors.counting()); System.out.println(count); DoubleSummaryStatistics dss = employees.stream() .collect(Collectors.summarizingDouble(Employee2::getSalary)); System.out.println(dss.getMax()); }
Single condition grouping: grouping streams according to employee status. Because after grouping, you get a Map set, key is the employee status, and value is a List set.
@Test public void test4() { Map<Employee2.Status, List<Employee2>> map = employees.stream() .collect(Collectors.groupingBy(Employee2::getStatus)); Set<Map.Entry<Employee2.Status, List<Employee2>>> set = map.entrySet(); Iterator<Map.Entry<Employee2.Status, List<Employee2>>> iterator = set.iterator(); while (iterator.hasNext()) { Map.Entry<Employee2.Status, List<Employee2>> entry = iterator.next(); System.out.println(entry.getKey()); System.out.println(entry.getValue()); } }
Multiple condition grouping: first group by employee status. If the status is the same, then group by employee age.
@Test public void test5() { Map<Employee2.Status, Map<String, List<Employee2>>> map = employees.stream() .collect(Collectors.groupingBy(Employee2::getStatus, Collectors.groupingBy((e) -> { if (e.getAge() <= 35) { return "adult"; } else if (e.getAge() <= 60) { return "middle age"; } else { return "old age"; } }))); Set<Employee2.Status> set = map.keySet(); Iterator<Employee2.Status> iterator = set.iterator(); while (iterator.hasNext()) { Employee2.Status next = iterator.next(); Map<String, List<Employee2>> listMap = map.get(next); System.out.println(next); System.out.println(listMap); } }
Employees are divided according to specific conditions. (employee salary greater than or equal to 5000 is a true partition; otherwise, it is a false partition).
@Test public void test6() { Map<Boolean, List<Employee2>> map = employees.stream() .collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000)); map.forEach((key,value) -> System.out.println("Key:" + key + ", Value:" + value)); }