1, Introduction to Stream
1.1 Stream API description
- Stream API(java.util.stream) introduces the true functional programming style into Java, providing simple and efficient operation
- Stream is a key abstract concept for processing collections in Java 8. It can specify operations on collections and perform very complex operations such as finding, filtering and mapping data. Using the Stream API to operate on the collection data is similar to a database query executed using SQL. You can also use the Stream API to perform operations in parallel
1.2 what is a Stream
Stream is a data channel used to manipulate the sequence of elements generated by data sources (sets, arrays, etc.). A collection stores data, and a stream calculates the collection elements
- Stream does not store elements in this province
- Stream does not change the source object, but returns a new stream that holds the result
- Stream is delayed and can only be executed when results are needed
1.3 Stream operation steps
-
Create Stream
Get a stream from a data source (such as a collection or array)
-
Intermediate operation
An intermediate operation chain can perform multiple operations to process the data of the data source
-
Terminate operation
Once the termination operation is executed, the intermediate operation chain is executed and the results are generated. After that, the created flow can no longer be used. If it is used, a new flow needs to be created

2, Stream usage
2.1 create execution flow
-
Create execution flow from collection
List<User> userList = User.getUserList(); //Create sequential flow Stream<User> userStream = userList.stream(); //Create parallel streams, and intermediate operations can be performed in parallel Stream<User> userParallelStream = userList.parallelStream();
The default stream and parallelStream methods are implemented in the Collection interface, so the Collection implementation class can call these two methods directly
-
Create execution flow from array
int[] intArr = {1,2,3,4,5,6}; IntStream intStream = Arrays.stream(intArr); int[] longArr = {1,2,3,4,5,6}; IntStream longStream = Arrays.stream(longArr); double[] doubleArr = {1.1,2.2,3.3}; DoubleStream stream = Arrays.stream(doubleArr); User[] userArr = {new User(1,"zhangsan",25),new User(2,"lisi",26)}; Stream<User> userStream = Arrays.stream(userArr);
The Arrays tool class provides a static stream method implementation, in which the Arrays of basic types int, long and double return the execution flow corresponding to the basic type
-
Created by the of method of Stream
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6); Stream<Boolean> booleanStream = Stream.of(true, false); Stream<Float> floatStream = Stream.of(1.1f, 2.2f, 3.3f);
When creating an execution flow of a basic data type through the of method, the execution flow of the wrapper type corresponding to the returned basic type
-
Create an infinite Stream through Stream's iterate() and generate()
Stream.iterate(0,t -> t+2).limit(10).forEach(System.out::println); Stream.generate(Math::random).limit(10).forEach(System.out::println);
Iterate always generates data through iteration. The first parameter is the starting value, and the subsequent lambda expression is the specific iteration logic. If it is not limited by the subsequent limit method, it will iterate all the time
generate generates data by repeatedly calling lambda expressions. If there is no limit, the lambda expressions inside will be called all the time
2.2 intermediate operation of stream
The intermediate operations of Stream can be connected to form a call chain (pipeline). Only when the pipeline executes the termination operation, the intermediate operation will be executed. Otherwise, the intermediate operation will not be processed, but will be processed at one time when the operation is terminated. This method is called "lazy evaluation"
-
Screening and slicing
//Filter out users older than 25. The filter parameter is the implementation of the predict function interface List<User> userList = User.getUserList(); userList.stream().filter(user -> user.getAge() >25).forEach(System.out::println);
//Limit the number of collection elements and output only three users List<User> userList = User.getUserList(); userList.stream().limit(3).forEach(System.out::println);
//Skip the set elements of the number of previous instructions. In the example, skip the first two List<User> userList = User.getUserList(); userList.stream().skip(2).forEach(System.out::println);
//distinct de duplication: remove duplicate elements through hashCode() and equals() of the elements generated by the stream List<User> userListDistinct = new ArrayList<User>(){ { new User(1,"lizhi",23); new User(1,"lizhi",23); new User(1,"lizhi",23); } }; userListDistinct.stream().distinct().forEach(System.out::println);
If the Stream has already performed the termination operation, calling the Stream API of the Stream again will cause an exception: java.lang.IllegalStateException: stream has already been operated upon or closed
-
mapping
//By mapping the elements of the original Stream to the Stream composed of new elements List<String> list = Arrays.asList("aa","bb","cc"); list.stream().map(String::toUpperCase).forEach(System.out::println); //Map the user entity collection to the user's name collection List<User> userList = User.getUserList(); Stream<String> nameStream = userList.stream().map(User::getName); nameStream.filter(name -> name.startsWith("li")).forEach(System.out::println); //flatmap takes a function as a parameter, maps each value in a stream to another stream, and then combines all streams into one stream Stream<Character> characterStream = list.stream().flatMap(StreamOperateTest::stringFormat); characterStream.forEach(System.out::println); /** Original writing */ Stream<Stream<Character>> streamStream = list.stream().map(StreamOperateTest::stringFormat); streamStream.forEach(stream -> stream.forEach(System.out::println)); public static Stream<Character> stringFormat(String string){ List<Character> list = new ArrayList<>(8); for (Character c: string.toCharArray()) { list.add(c); } return list.stream(); }
Mapping transforms the original Stream stream into a new Stream stream through the mapping relationship
-
sort
//Default sort List<Integer> integerList = Arrays.asList(12, 95, 32, 2, 95, -2, 35); integerList.stream().sorted().forEach(System.out::println); //Custom sorting List<User> userList = User.getUserList(); userList.stream().sorted(Comparator.comparingInt(User::getAge)).forEach(System.out::println);
2.3 termination
-
Find and match
//Check that all elements match List<User> userList = User.getUserList(); boolean allMatch = userList.stream().allMatch(user -> user.getAge() > 24); //Check to see if any of the elements match boolean anyMatch = userList.stream().anyMatch(user -> user.getAge() > 25); //Check if there are no matching elements boolean noneMatch = userList.stream().noneMatch(user -> user.getAge() > 25); //Find first element Optional<User> firstUser = userList.stream().findFirst(); //Find any element Optional<User> anyUser = userList.stream().findAny(); //Count the number of elements in the stream long count = userList.stream().count(); //Maximum value in the statistical flow. If there are multiple maximum ages of users to be compared, any one will be returned Optional<User> maxUser = userList.stream().max(Comparator.comparing(User::getAge));
-
reduction
//Combine the elements in the flow repeatedly to get a value //The and the first parameter of the element in the calculation set are the starting values and also participate in the operation List<Integer> integerList = Arrays.asList(5, 6, 8, 22, 72, 365, 85); Integer reduce = integerList.stream().reduce(0, Integer::sum); //The User is transformed into an age stream through map without repeated operation of the initial value Optional<Integer> allAge = userList.stream().map(User::getAge).reduce(Integer::sum);
-
collect
//Collect the data after the operation into a collection List<User> userList = User.getUserList(); List<User> collect = userList.stream().filter(user -> user.getAge() > 25).collect(Collectors.toList()); Set<User> userSet = userList.stream().filter(user -> user.getName().startsWith("zhu")).collect(Collectors.toSet());