What is flow operation
The Java 8 API adds a new abstraction called streaming Stream, which allows you to process data in a declarative way.
Stream provides a high-level abstraction of Java set operations and expressions in an intuitive way similar to querying data from a database using SQL statements.
Stream API can greatly improve the productivity of Java programmers and make them write efficient, clean and concise code.
This style regards the set of elements to be processed as a flow, which is transmitted in the pipeline and can be processed on the nodes of the pipeline, such as filtering, sorting, aggregation, etc.
The element flow is processed by intermediate operation in the pipeline, and the final operation gets the result of the previous processing.
1. Flow operation example
1.1 create entity class
public class Person {
private String name;
private Integer age;
private Integer score;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getScore() {
return score;
}
public void setScore(Integer score) {
this.score = score;
}
public Person() {
}
public Person(String name, Integer age, Integer score) {
this.name = name;
this.age = age;
this.score = score;
}
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
1.2 traditional object initialization method
public class Program {
public static void main(String[] args) {
//Using constructors to set object information
//Person xiaomign = new Person("Xiaoming", 28, 90);
//Use getter and setter to set object information
Person xiaoming = new Person();
xiaoming.setName("Xiao Ming");
xiaoming.setAge(18);
xiaoming.setScore(90);
}
}
1.3 initializing objects with streaming operations
1.3.1 modify entity class
public class Person {
private String name;
private Integer age;
private Integer score;
public String getName() {
return name;
}
public Person setName(String name) {
this.name = name;
return this;
}
public Integer getAge() {
return age;
}
public Person setAge(Integer age) {
this.age = age;
return this;
}
public Integer getScore() {
return score;
}
public Person setScore(Integer score) {
this.score = score;
return this;
}
public Person() {
}
public Person(String name, Integer age, Integer score) {
this.name = name;
this.age = age;
this.score = score;
}
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
1.3.2 use flow operation
//Streaming operation
xiaoming.setName("Xiao Ming").setAge(20).setScore(100);
2. Flow operation of set
The streaming operation of collection is a new feature of Java 8. The streaming operation is not a data structure, and it is not responsible for any data storage. It is more like an iterator, which can get every data in the data source orderly, and can perform some operations on these data. The return value of each method of a streaming operation is the flow itself.
2.1 three steps of flow operation
2.1.1 get data source: set, array
set up data sources
public class Data {
/**
* data source
*/
public static ArrayList<Person> getData() {
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person("Xiao Ming", 18, 100));
list.add(new Person("Xiaoli", 19, 70));
list.add(new Person("Xiao Wang", 22, 85));
list.add(new Person("Xiao Zhang", 20, 90));
list.add(new Person("Small black", 21, 95));
return list;
}
}
How to get the data source
public class Program {
public static void main(String[] args) {
// Get data source mode 1
Stream stream = Data.getData().stream();
// Get data source mode 2
Stream.of(Data.getData());
// Get data source mode 3
//Data source is array
}
}
2.1.2 data processing: filtering, sorting, mapping, etc. (intermediate operation)
Intermediate operation 1: filter
Filter data using filter custom criteria
// Intermediate operation 1: filter
// Filter is a filter. You can customize a filter condition to keep the elements in the flow that meet the condition
// Find students with scores less than 80 in the set
List<Person> list = Data.getData().stream()
.filter(ele -> ele.getScore() < 80)
.collect(Collectors.toList());
System.out.println(list);
Intermediate operation 2: distinct
Using distinct to realize de duplication
Add duplicate data to the data source
list.add(new Person("Small black", 21, 95)); //At this time, there are two small black in the list
Override hashCode() and equals() methods in entity classes
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name) &&
Objects.equals(age, person.age) &&
Objects.equals(score, person.score);
}
public int hashCode() {
return Objects.hash(name, age, score);
}
De duplication rules:
Determine the hashCode() of the object first
If hashCode() is the same, judge equals()
// Intermediate operation 2: distinct
// distinct: extract different elements from the collection
// De duplication rules:
// 1. First determine the hashCode()
// 2. If hashCode() is the same, judge equals()
Data.getData().stream().distinct().forEach(System.out::println);
Note: if the data of small black is the same but two copies need to be saved, you can return a random number in the hashCode() method, and the probability of the random number is the same. To ensure stability, you can change the equals() method to return false, so that two small black with the same information can be retained.
Intermediate operation 3: sorted
Use the sorted() method to sort grades in ascending order
Require entity class to implement compatible interface and override method
// Intermediate operation 3: sorted
// sorted: sorts the returned elements
// sorted(): requires the entity class to implement the compatible interface and override the method
Data.getData().stream().sorted().forEach(System.out::println);
Intermediate operation 4: limit
Take the first three data in the data source
// Intermediate operation 4: limit
// Limit: limit, only the data in the flow that is located by the front finger
// Take the first three data in the data source
Data.getData().stream().limit(3).forEach(System.out::println);
Intermediate operation 5: skip
// Intermediate operation 5: skip
// Skip: skip over
// Skip the first three elements and take the rest
Data.getData().stream().skip(3).forEach(System.out::println);
Intermediate operation 6: map
Element mapping, replacing elements in the stream with specified elements
Use map to replace an object with its name
// Intermediate operation 6: map
// map: element mapping, replacing the elements in the stream with the specified elements
// Replace the Person object in the stream with their name
Data.getData().stream().map(ele -> ele.getName()).forEach(System.out::println);
2.1.3 data integration in convection: transfer to set, quantity (final operation)
Final operation 1: collect
Convert to List
public class Program {
public static void main(String[] args) {
// Get data source mode 1
Stream<Person> stream = Data.getData().stream();
// Final operation 1: collect, used with Collectors
// Convert elements in a collection to a List
List<Person> list = stream.collect(Collectors.toList());
System.out.println(list);
}
}
Operation result
Convert to set
// Convert elements in a collection to a Set
Set<Person> set = stream.collect(Collectors.toSet());
System.out.println(set);
Operation result
Convert to map
// Convert to Map (name as key, score as value)
// Mode 1
// Map<String, Integer> map = stream.collect(Collectors.toMap(
// ele -> ele.getName(),
// ele -> ele.getScore()
// ));
// Mode 2
Map<String, Integer> map = stream.collect(Collectors.toMap(
Person::getName,
Person::getScore
));
Operation result
Final operation 2: reduce
The thought of reduce
For example, when calculating the sum of elements in an array, the sum of the first two numbers will be calculated first, and then the sum of the first two numbers and the third number will be calculated. After calculating the result, the sum of the three numbers and the fourth number will be added, and so on.
Calculating the sum of data in an array
// Final action 2: reduce (summarize data)
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Optional<Integer> res = stream1.reduce((n1, n2) -> n1 + n2);
// Get the final return value
System.out.println(res.get());
Using reduce to calculate the sum of the scores in the Person object
// Calculate the sum of scores in Person
Optional<Person> res = stream.reduce(
(n1, n2) -> new Person().setScore(n1.getScore() + n2.getScore())
);
System.out.println(res.get().getScore());
Disadvantages: the above method will generate a temporary object each time, resulting in unnecessary performance loss
Using reduce to calculate the sum of the scores in the Person object (optimization)
// Calculate the sum of scores in Person (use temporary variables to reduce performance overhead)
Person temp = new Person();
Optional<Person> res = stream.reduce(
(n1, n2) -> temp.setScore(n1.getScore() + n2.getScore())
);
System.out.println(res.get().getScore());Final operation 3: max and min
Use max to find the Person with the highest score in Person
// Final operation 3: max and min
// Requirement 1: find the information of the highest achievers in the collection
Person max = stream.max(
(ele1, ele2) -> ele1.getScore() - ele2.getScore()
).get();
System.out.println(max);
Use min to find the Person with the lowest score in Person
// Requirement 2: find information about the lowest achievers in the set
Person min = stream.min(
(ele1, ele2) -> ele1.getScore() - ele2.getScore()
).get();
System.out.println(min);
Final operation 4: matching
Use anyMatch to see if there are people in the collection with scores higher than 80
// Judge whether students with scores greater than 80 are included in the set
boolean res1 = stream.anyMatch((ele) -> ele.getScore() > 80);
System.out.println(res1);
Use allMatch to see if the scores in the collection are all higher than 60
//See if all of the people in the collection are above 60
boolean res2 = stream.allMatch((ele) -> ele.getScore() > 60);
System.out.println(res2);
Use noneMatch to see if people in the collection don't have scores below 80
boolean res3 = stream.noneMatch((ele) -> ele.getScore() < 80);
System.out.println(res3);
Final operation 5: count
Use count to calculate how many pieces of data are in metadata
// Final operation 5: find how many elements are in the metadata
long count = stream.count();
System.out.println(count);
Final operation 6: forEach
Traversing elements in a collection using forEach
// Final operation 6: forEach
// stream.forEach(ele -> System.out.println(ele));
stream.forEach(System.out::println);
Final action 7: findFirst and findAny FindFirst: get the first element in the stream FindAny: get any element in the stream (not random get element) for a serial stream, the result is the same as findFirst findAny used in a parallel stream, which may be the same as or different from findFirst
// FindFirst: get the first element in the stream
// FindAny: get any element in the stream (not random)
//For a serial stream, the result is equivalent to findFirst
//findAny may or may not be used in parallel flows as findFirst
System.out.println(Data.getData().parallelStream().findFirst());
System.out.println(Data.getData().stream().findFirst());
System.out.println(Data.getData().parallelStream().findAny());
System.out.println(Data.getData().stream().findAny());
Precautions for final operation
Why is it called the final operation?
Person max = stream.max(
(ele1, ele2) -> ele1.getScore() - ele2.getScore()
).get();
Person min = stream.min(
(ele1, ele2) -> ele1.getScore() - ele2.getScore()
).get();
The error message indicates that the stream is being processed or has been closed. If it is closed and called again, the error will be reported, which is why it is called the final operation.
3. parallel flow
3.1 way to obtain parallel flow
// Parallel flow
// Two ways to get parallel flow
Data.getData().stream().parallel();
Data.getData().parallelStream();
3.2 comparison of parallel flow and serial flow
// Serial stream: 19920ms
// Parallel flow: 12204ms
long startTime = System.currentTimeMillis();
//LongStream.rangeClosed(0L, 50000000000L)
// .reduce(Long::sum);
LongStream.rangeClosed(0L, 50000000000L)
.parallel()
.reduce(Long::sum);
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
3.3 flatMap
String[] array = {"hello", "world"};
// Need to get all characters list - > H, e, l, l, O, W, O, R, l, D
// Arrays.stream(array)
// .map(ele -> ele.split(""))
// .forEach(ele -> System.out.println(ele.length));
System.out.println(Arrays.stream(array)
.map(ele -> ele.split(""))
.flatMap(Arrays::stream)
.collect(Collectors.toList()));
4.Collectors
Collectors is a tool class that provides several methods to return an implementation class object of Collector interface
4.1 maxBy
Gets the largest element in the flow through the specified rule
System.out.println(Data.getData().stream()
.collect(Collectors.maxBy((ele1, ele2) -> ele1.getScore() - ele2.getScore())));
4.2 minBy
Gets the smallest element in the flow through the specified rule
System.out.println(Data.getData().stream()
.collect(Collectors.minBy((ele1, ele2) -> ele1.getScore() - ele2.getScore())));
4.3 joining
Merge, the elements in the stream are spliced in the form of strings
// Spell the name in Person into a string
String res1 = Data.getData().stream()
.map(Person::getName)
.collect(Collectors.joining());
System.out.println(res1);
String res2 = Data.getData().stream()
.map(Person::getName)
.collect(Collectors.joining("-"));
System.out.println(res2);
String res3 = Data.getData().stream()
.map(Person::getName)
.collect(Collectors.joining("-", "{", "}"));
System.out.println(res3);
4.4 summingInt
Calculate the sum of int type, and map the elements in the flow to the sum of int type elements
Sum the performance of Person object
// Sum the performance of Person object
System.out.println(Data.getData().stream()
.collect(Collectors.summingInt(ele -> ele.getScore())));
4.5 averagingInt
Average int
Calculate the average of failing students
System.out.println(Data.getData().stream()
.filter(ele -> ele.getScore() < 60)
.collect(Collectors.averagingInt(Person::getScore)));
4.6 summarizingInt
Map the elements in the flow to the elements of type int to obtain the description information of these data
System.out.println(Data.getData().stream()
.collect(Collectors.summarizingInt(ele -> ele.getScore())));
If you want to get more learning materials, please comment on [learning] below the comment
Link: https://juejin.im/post/5e15e9fc5188253a9b1bf858