background
Java 8 has been around for a few years, and Java 12 has been around for a while, but many projects are still working in Java 1.7. And many of the new features of java8 are revolutionary, such as the optimization of various collections, lambda expressions, etc., so we still have to understand the charm of java8.
Today we will learn java8 Stream, does not need the theoretical basis, directly can get started to use.
The reason WHY I approached Stream was that I wanted to conduct a data analysis of user income and consumption. The original statistical filtering groups were intended to be presented using SQL to get results directly from mysql. But in the operation, we found that such frequent access to the database, the performance will be greatly affected, the analysis speed will be slow. So we want to be able to access the database once and get all the data, and then put it in memory for analysis and statistical filtering.
Then I looked at the STREAM API and saw that this was what I wanted.
A
A Stream is called a “Stream” in Java, and we often use a Stream to perform pipelining operations on collections. A stream is like a factory. It just needs to feed collections, commands, and parameters into the pipeline to produce the desired result. Such pipelining can greatly simplify code and reduce operations.
Ii. Stream
Original collection - > Stream - > various operations (filtering, grouping, statistics) - > Terminal operationsCopy the code
The operation of a Stream is usually done by converting a collection to a Stream, and then by various operations such as filtering, filtering, grouping, and calculation. The final terminal operation is to convert it into the data we want. The form of this data is generally a set, and sometimes it will output count as required. Examples will be given below.
Examples of API functions
First, define a user object with four member variables: name, age, gender, and native place:
import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.log4j.Log4j; @data @noargsconstructor @log4j @constructor public class User {// private String name; Private Integer age; // private Integer sex; Private String address; }Copy the code
Lombok simplifies the entity class code here.
Then create the required collection data, which is the source data:
List<User> list= arrays.asList (new User("Iron Man", 40, 0."Washington"),
new User("Spider-man", 20, 0,"Washington"),
new User("Zhao Liying", 30, 1,Wuhan city, Hubei Province),
new User("James", 35, 0,"Los Angeles"),
new User("Li Shimin", 60, 0,"Taiyuan, Shanxi Province"),
new User("CAI Xukun", 20, 1."Xi 'an, Shaanxi province"),
new User("Grandpa of the Gourd Baby.", 70, 0,"Taiyuan, Shanxi Province"));Copy the code
3.1 the filter
Create stream()/parallelStream()
- Stream () : serial stream
- ParallelStream () : Parallel streams
2) filter (T-> Boolean)
For example, to filter users over the age of 40, you can write:
List<User> filterList = list.stream().filter(user -> user.getAge() >= 40)
.collect(toList());
Copy the code
In filter, the -> arrow is followed by a Boolean value that can be used to write any filter criteria. In other words, it can be used to write anything that can be used in SQL
Print result:
3) Distinct weight removal
This is similar to the DISTINCT keyword in SQL. In order to see the effect, here to add a repeat of the original set, choose Iron Man, avengers 4 tragically killed iron Man, people are still more sad.
List<User> list= Arrays.asList(
new User("Iron Man", 40, 0."Washington"),
new User("Iron Man", 40, 0."Washington"),
new User("Spider-man", 20, 0,"Washington"),
new User("Zhao Liying", 30, 1,Wuhan city, Hubei Province),
new User("James", 35, 0,"Los Angeles"),
new User("Li Shimin", 60, 0,"Taiyuan, Shanxi Province"),
new User("CAI xukun",18,1,"Xi 'an, Shaanxi"), new User("Gourd baby's grandfather", 70, 0,"Taiyuan, Shanxi Province"));Copy the code
DistinctList = filterlist.stream ().distinctList ().collect(toList()); distinctList <User> distinctList = filterlist.stream ().distinctList ().collect(toList());Copy the code
Print result:
4) Sorted
If the classes of the elements in the stream implement the Comparable interface, i.e. have their own sorting rules, then the sorted() method can be called directly to sort the elements, as in:
Comparator.comparingInt
Copy the code
Instead, we call sorted((T, T) -> int) to implement the Comparator interface.
//sorted()
List<User> sortedList = distinctList.stream().sorted(Comparator.comparingInt(User::getAge))
.collect(toList());
Copy the code
Print result:
The results are sorted by age from youngest to oldest.
5) Limit () returns the first n elements
If you want to know who the youngest is, you can do the following:
//limitReturn the first n elements List<User>limitList = sortedList.stream().limit(1)
.collect(toList());
Copy the code
6) the skip ()
As opposed to limit, skip means to skip, to remove the first n elements.
Print result:
Sure enough, the first two were removed, leaving only the oldest gourd baby grandpa.
3.2 mapping
1) the map – > R (T)
Map is to convert data of type T into data of type R. For example, we want to set up a new list to store all the city information of the user.
//map(T->R)
List<String> cityList = list.stream().map(User::getAddress).distinct().collect(toList());
Copy the code
Print result:
2) flatMap(T -> Stream)
Map each element T in the flow to a flow, and concatenate each flow into a flow.
//flatMap(T -> Stream<R>)
List<String> flatList = new ArrayList<>();
flatList.add("Sing and dance");
flatList.add("Rape, basketball, music");
flatList = flatList.stream().map(s -> s.split(",")).flatMap(Arrays::stream).collect(toList());
Copy the code
Print result:
In this case, the data in the original set is separated by commas. After using split, we get Stream<String[]>, which is composed of String array, and we want to use flatMap
Arrays::stream
Convert Stream<String[]> to Stream, and then connect the streams to form the complete singing, dancing, rap, basketball, and music.
3.3 find
1) allMatch (T-> Boolean)
Check whether all the parameter behaviors are met. If these users are the list of Internet cafe users, it is necessary to check whether everyone is 18 years old or not.
boolean isAdult = list.stream().allMatch(user -> user.getAge() >= 18);
Copy the code
Print result:
true
Copy the code
2) anyMatch (T-> Boolean)
Check if any element satisfies a given condition, for example, if you want to know if there are girls in the class list.
Boolean isGirl = list.stream().anymatch (user -> user.getsex () == 1); Boolean isGirl = list.stream().anymatch (user -> user.getsex () == 1);Copy the code
Print result:
true
Copy the code
This indicates that a girl exists in the set.
3) noneMatch(T -> Boolean)
Whether any elements in the stream match the given T -> Boolean condition.
Like checking for users from Paris.
boolean isLSJ = list.stream().noneMatch(user -> user.getAddress().contains("Paris"));
Copy the code
Print result:
true
Copy the code
Printing true indicates that there are no users in Paris.
4) findFirst(): Finds the first element
Optional<User> fristUser = list.stream().findFirst();
Copy the code
Print result:
User(name= Iron Man, age=40, sex=0, address= Washington)Copy the code
5) findAny(): findAny element
Optional<User> anyUser = list.stream().findAny();
Copy the code
Print result:
User(name= Iron Man, age=40, sex=0, address= Washington)Copy the code
Here we see that findAny always returns the first element as well, so why make the distinction? Because the parallelStream parallelStream() does find any element.
Optional<User> anyParallelUser = list.parallelStream().findAny();
Copy the code
Print result:
Optional[User(name= lI Shimin, age=60, sex=0, address= taiyuan, Shanxi Province)]Copy the code
3.4 Inductive calculation
1) Find the total number of users
long count = list.stream().collect(Collectors.counting());
Copy the code
We can abbreviate it as:
long count = list.stream().count();
Copy the code
Running results:
8
Copy the code
2) Get the maximum and minimum value of an attribute
Optional<User> Max = list.stream().collect(Collectors. MaxBy (Comparator.comparing(User::getAge))); Optional<User> min = list.stream().collect(Collectors. MinBy (Comparator.comparing(User::getAge)));Copy the code
Running results:
3) What is the sum of the ages
Int totalAge = list.stream().collect(Collectors. SummingInt (User::getAge));Copy the code
Running results:
313
Copy the code
We often record money in BigDecimal, assuming we want to sum BigDecimal:
// Get the list object amount, Using reduce aggregate functions, the realization of accumulator BigDecimal sum = myList. Stream (). The map (User: : getMoney). Reduce (BigDecimal. ZERO, BigDecimal: : add);Copy the code
4) Average age
Double avgAge = list.stream().collect(Collectors. AveragingInt (User::getAge));Copy the code
Running results:
39.125
Copy the code
5) Get the number, sum, maximum and minimum of elements at one time
IntSummaryStatistics statistics = list.stream().collect(
Collectors.summarizingInt(User::getAge));
Copy the code
Running results:
6) String concatenation
To concatenate the user’s name into a string separated by commas.
String names = list.stream().map(User::getName)
.collect(Collectors.joining(","));
Copy the code
Running results:
Iron Man, Iron Man, Spider-Man, Zhao Liying, James, Li Shimin, CAI Xukun, hulu Wa's grandfatherCopy the code
3.5 grouping
In database operations, we often use the GROUP BY keyword to GROUP queried data. Streaming processing in java8 also provides grouping capabilities. GroupingBy is used to group the Collectors.
1) Users can be grouped according to their cities
Map<String, List<User>> cityMap = list.stream()
.collect(Collectors.groupingBy(User::getAddress));
Copy the code
The result is a map where key is a unique city name and value is a list of users belonging to that city. Grouping has been implemented.
2) Level 2 grouping, first by city and then by gender
Map<String, Map<Integer, List<User>>> group = list.stream().collect(Collectors. GroupingBy (User::getSex))). // Group by genderCopy the code
Running results:
3) If you only want to count the number of users in each city, you do not need the corresponding list
Grouped by city and counted:
Map<String, Long> cityCountMap = list.stream()
.collect(Collectors.groupingBy(User::getAddress,Collectors.counting()));
Copy the code
Running results:
4) Of course, it can also be filtered and then grouped and counted
Map<String,Long> map = list.stream().filter(user -> user.getAge() <= 30)
.collect(Collectors.groupingBy(User::getAddress,Collectors.counting()));
Copy the code
Running results:
5) partitioningBy
The difference between partitioning and grouping is that partitions are divided according to true and false, so the lambda accepted by partitioningBy is also T -> Boolean
Map<Boolean, List<User>> part = list.stream().collect(partitioningBy(User -> user.getage () <= 30));Copy the code
Running results:
conclusion
We’ve used a lot of stream functionality so far, and it feels a little dizzying and omnipotent. There’s a lot more that stream can do.
We can learn to use stream more, refactoring the original complex SQL query, complex code for loop over and over again, make the code more concise and easy to understand, readable.
Redis Project 1: Building the Knowledge Graph
Redis Topics (2) : The underbelly of Redis data structures
Author: Yang Heng
Source: Creditease Institute of Technology