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