The Java 8 API has added a new abstraction called a Stream that lets you process data in a declarative way. The Stream API can greatly improve the productivity of Java programmers, allowing programmers to write efficient, clean, and concise code. This style treats the collection of elements to be processed as a stream that travels through a pipe and can be processed at the nodes of the pipe, such as filtering, sorting, aggregating, and so on. The element stream is processed by intermediate operation in the pipe, and finally the result of the previous processing is obtained by terminal operation.
Why summarize the Java 8 Stream API systematically this time? To put it simply, we don’t care about performance, we just want to install X, and make the X install better, that’s all!
Stream Basics
process
Create a flow → intermediate action for a flow → final action for a flow
Create a flow
What elements do we need to put into the stream? Common apis are:
List.stream (); // Use one or more elements to create stream.of (T value) stream.of (T... Stream (T[] array) // Create an empty stream.empty () // Merge stream.concat (stream <? extends T> a, Stream<? Extends T> b) // Generate (Supplier<T> s) // Iterate to generate an infinite Stream. Iterate (final T seed, iterate) final UnaryOperator<T> f)Copy the code
An intermediate operation of a stream
// Element filterlimitSkip distinct // map flatmap // SortCopy the code
The final operation of the stream
What result do we want from the flow’s final operation on the element
Construct test data
Employee Entity Class
/** * Employee entity class *@author Erwin Feng
* @since2020/4/27 2:10 * /
public class Employee {
/** Employee ID */
private Integer id;
/** Employee name */
private String name;
/** Employee salary */
private Double salary;
/** constructor, getter and setter, toString */
}
Copy the code
Test data list
[{"id":1."name":"Jacob"."salary":1000
},
{
"id":2."name":"Sophia"."salary":2000
},
{
"id":3."name":"Rose"."salary":3000
},
{
"id":4."name":"Lily"."salary":4000
},
{
"id":5."name":"Daisy"."salary":5000
},
{
"id":6."name":"Jane"."salary":5000
},
{
"id":7."name":"Jasmine"."salary":6000
},
{
"id":8."name":"Jack"."salary":6000
},
{
"id":9."name":"Poppy"."salary":7000}]Copy the code
Stream API Test
The filter to filter
Need: Find a list of employees whose salary is 5000
List<Employee> employees = list.stream().filter(employee -> employee.getSalary() == 5000)
.peek(System.out::println)
.collect(Collectors.toList());
Assert.assertEquals(2, employees.size());
Copy the code
The map mapping
Requirement: Put the employee whose salary is more than 5000 into the Leader object
List<Leader> leaders = list.stream().filter(employee -> employee.getSalary() > 5000).map(employee -> {
Leader leader = new Leader();
leader.setName(employee.getName());
leader.setSalary(employee.getSalary());
return leader;
}).peek(System.out::println).collect(Collectors.toList());
Assert.assertEquals(3, leaders.size());
Copy the code
FlatMap Horizontal mapping
Requirement: Convert a multidimensional list to a one-dimensional list
Description:
We divided the salary between 1000 and 3000 into a list, the salary between 4000 and 5000 into a list, and the salary between 6000 and 7000 into a list.
Combine these three lists to form a multidimensional list.
List<Employee> employees = multidimensionalList.stream().flatMap(Collection::stream).collect(Collectors.toList());
Assert.assertEquals(9, employees.size());
Copy the code
Sorted order
Need: Sort by salary
// Rank your salary in ascending order
List<Employee> employees = list.stream().sorted(Comparator.comparing(Employee::getSalary)).peek(System.out::println).collect(Collectors.toList());
// Salary in ascending orderList<Employee> employees2 = list.stream().sorted(Comparator.comparing(Employee::getSalary).reversed()).peek(System.out::println).collect(Collectors. toList());Copy the code
Min min
double minValue = list.stream().mapToDouble(Employee::getSalary).min().orElse(0);
Assert.assertEquals(1000, minValue, 0.0);
Employee employee = list.stream().min(Comparator.comparing(Employee::getSalary)).orElse(null);
assertemployee ! =null;
Assert.assertEquals(employee.getSalary(), minValue, 0.0);
Copy the code
Max maximum
double maxValue = list.stream().mapToDouble(Employee::getSalary).max().orElse(0);
Assert.assertEquals(7000, maxValue, 0.0);
Copy the code
The average business,
double sum = list.stream().mapToDouble(Employee::getSalary).sum();
double averageValue = list.stream().mapToDouble(Employee::getSalary).average().orElse(0);
Assert.assertEquals(sum / list.size(), averageValue, 0.0);
Copy the code
Match match
// All elements in the allMatch collection must meet the condition to return true
// The salary is 1000 or more
boolean isAllMatch = list.stream().allMatch(employee -> employee.getSalary() >= 1000);
Assert.assertTrue(isAllMatch);
// The anyMatch set returns true as long as one of the elements meets the criteria
// Is there any salary greater than or equal to 7000
boolean isAnyMatch = list.stream().anyMatch(employee -> employee.getSalary() >= 7000);
Assert.assertTrue(isAnyMatch);
// Return true if there are no elements in the noneMatch collection
// No salary less than 1000
boolean isNoneMatch = list.stream().noneMatch(employee -> employee.getSalary() < 1000);
Assert.assertTrue(isNoneMatch);
Copy the code
Distinct to heavy
The default distinct() does not accept arguments and is de-weighted based on Object#equals(Object). According to the API, this is an operation with intermediate states.
List<Employee> employees = list.stream().distinct().collect(Collectors.toList());
Assert.assertEquals(9, employees.size());
Copy the code
We can use StreamEx if we want to de-duplicate an object based on an attribute
// Use StreamEx to remove weights
List<Employee> employees2 = StreamEx.of(list).distinct(Employee::getSalary).collect(Collectors.toList());
Assert.assertEquals(7, employees2.size());
Copy the code
You can also use the JDK Stream API
private static <T>Predicate<T> distinctByKey(Function<? superT, ? > keyExtractor) {
Map<Object, Boolean> result = new ConcurrentHashMap<>();
return t -> result.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
List<Employee> employees3 = list.stream().filter(distinctByKey(Employee::getSalary)).collect(Collectors.toList());
Assert.assertEquals(7, employees3.size());
Copy the code
Reduce cutting
Requirement: Calculate the sum of salary
// Convert the employee list to the salary list
// Then calculate the total salary
double salarySum = list.stream().map(Employee::getSalary).reduce(Double::sum).orElse(0.0);
double sum = list.stream().mapToDouble(Employee::getSalary).sum();
Assert.assertEquals(salarySum, sum, 0.0);
Copy the code
Alternatively, we can set an identifier value for the summation function
double salarySum5 = list.stream().map(Employee::getSalary).reduce(1.00, Double::sum);
Assert.assertEquals(salarySum5, sum + 1.0.0);
Copy the code
Termination result of the Collector flow
// Joining string
String employeeNames = list.stream().map(Employee::getName).collect(Collectors.joining(","));
System.out.println(employeeNames); // Jacob, Sophia, Rose, Lily, Daisy, Jane, Jasmine, Jack, Poppy
// Return a List
List<String> employeeNameList = list.stream().map(Employee::getName).collect(Collectors.toList());
System.out.println(employeeNameList);
// return a Set
Set<String> employeeNameSet = list.stream().map(Employee::getName).collect(Collectors.toSet());
System.out.println(employeeNameSet);
// Return a Vector
Vector<String> employeeNameVector = list.stream().map(Employee::getName).collect(Collectors.toCollection(Vector::new));
System.out.println(employeeNameVector);
// Return a Map
Map<Integer, String> employeesMap = list.stream().collect(Collectors.toMap(Employee::getId, Employee::getName));
System.out.println(employeesMap);
Copy the code
The count statistics
Need: Number of employees with a salary of 5000
Do not use the flow
int count2 = 0;
for (Employee employee : list) {
if (employee.getSalary() == 5000) {
count2++;
}
}
System.out.println(count2);
Copy the code
Use the stream
long count3 = list.stream().filter(employee -> employee.getSalary() == 5000).count();
Assert.assertEquals(count3, count2);
Copy the code
SummarizingDouble statistical analysis
DoubleSummaryStatistics employeeSalaryStatistics = list.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println("employee salary statistics:" + employeeSalaryStatistics);
DoubleSummaryStatistics employeeSalaryStatistics2 = list.stream().mapToDouble(Employee::getSalary).summaryStatistics();
System.out.println("employee salary statistics2:" + employeeSalaryStatistics2);
Copy the code
{count=9, sum=39000.000000, min=1000.000000, average=4333.333333, Max =7000.000000}
PartitioningBy partition
It is divided into two sections that satisfy the condition (true) and that do not satisfy the condition (false)
Need: Find the employee whose salary is more than 5000
Map<Boolean, List<Employee>> map = list.stream().collect(Collectors.partitioningBy(employee -> employee.getSalary() > 5000));
System.out.println("true:" + map.get(Boolean.TRUE));
System.out.println("false:" + map.get(Boolean.FALSE));
Copy the code
True :[Employee{id=7, name=’Jasmine’, salary=6000.0}, Employee{id=8, name=’Jack’, salary=6000.0}, Employee{id=8, name=’Jack’, salary=6000.0}, Name = ‘Poppy, salary = 7000.0}]
False :[Employee{id=1, name=’Jacob’, salary=1000.0}, Employee{id=2, name=’Sophia’, salary=2000.0}, Employee{id=2, name=’Sophia’, salary=2000.0}, Name =’Rose’, salary=3000.0}, Employee{id=4, name=’Lily’, salary=4000.0}, Employee{id=5, name=’Daisy’, salary=5000.0}, The Employee {id = 6, name = ‘Jane’ salary = 5000.0}]
GroupingBy grouping
Requirements: Group employees according to salary
Map<Double, List<Employee>> map = list.stream().collect(Collectors.groupingBy(Employee::getSalary));
System.out.println(map);
Copy the code
Another example: Salary 1 > Total (Salary * number of employees)
Map<Double, Double> map3 = list.stream().collect(Collectors.groupingBy(Employee::getSalary, Collectors.summingDouble(Employee::getSalary)));
System.out.println(map3);
Copy the code
Parallel computing
Simply put, this is to start multiple threads of computation
private static void cal(Employee employee) {
try {
long sleepTime = employee.getSalary().longValue();
TimeUnit.MILLISECONDS.sleep(sleepTime);
logger.info("employee name: {}", employee.getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.stream().parallel().forEach(StreamTest::cal);
Copy the code
2020-05-15 01:47:14.231 [ForkJoinPool.com monpool-worker-4] infom.fengwenyi. Study_stream. streamtest-employee name: Jacob 2020-05-15 01:47:15.226 [ForkJoinPool.com monpool-worker-2] infom.fengwenyi. Study_stream.streamtest-employee name: Sophia 2020-05-15 01:47:16.226 [ForkJoinPool.com monpool-worker-1] info.fengwenyi. Study_stream. streamtest-employee name: Rose 2020-05-15 01:47:17.226 [ForkJoinPool.com monpool-worker-3] infom.fengwenyi. Study_stream.streamtest-employee Name: Lily 2020-05-15 01:47:18.225 [main] info.fengwenyi. Study_stream. streamtest-employee name: Jane 2020-05-15 01:47:18.228 [ForkJoinPool.com monpool-worker-7] infom.fengwenyi. Study_stream.streamtest-employee name: Daisy 2020-05-15 01:47:19.226 [ForkJoinPool.com monpool-worker-5] infom.fengwenyi. Study_stream.streamtest-employee name: Jack 2020-05-15 01:47:19.228 [ForkJoinPool.com monpool-worker-6] infom.fengwenyi. Study_stream.streamtest-employee name: Jasmine 2020-05-15 01:47:21.234 [ForkJoinPool.com monpool-worker-4] infom.fengwenyi. Study_stream.streamtest-employee name: PoppyCopy the code
File Operation
try (PrintWriter printWriter = new PrintWriter(Files.newBufferedWriter(Paths.get(tempFilePath)))) { // Use try to automatically close the stream
list.forEach(printWriter::println);
list.forEach(employee -> printWriter.println(employee.getName())); // Write the employee's name to the file
}
// Read the employee's name from the file
List<String> s = Files.lines(Paths.get(tempFilePath)).peek(System.out::println).collect(Collectors.toList());
Copy the code
The test code
Study Java 8 Stream API
Learning links
- Noodlespan > Stream series
- The Streams API in Java 8
- New in Java8 -Stream API common full version
- Stream In Java