brief introduction
Two of the most important changes in Java 8 are Lambda expressions and the Stream API(java.util.stream. *)
Stream is a key abstract concept for processing collections in Java 8. It can specify the operations you want to perform on collections, and can perform very complex operations such as finding, filtering and mapping data
Using Stream API to operate collection data is similar to using SQL to execute database queries. You can also use Stream API to perform operations in parallel. In short, Stream API provides an efficient and easy-to-use way to process data
What is Stream
What is a stream?
It is a data channel, which is used to operate the element sequence generated by the data source (set, array, etc.). "Set is about data, and flow is about calculation!"
be careful:
- Stream itself does not store elements
- Streams do not change the source object; instead, they return a new Stream that holds the result
- Stream operations are delayed, which means they wait until they are needed
There are three steps to the operation of Stream
Create Stream
A data source (e.g. collection, array) to obtain a stream
Create a stream through the Stream() or parallelStream() provided by the Collection series Collection
@Test public void createStream(){ // 1: stream() or parallelStream() provided through Collection series Collection List list = new ArrayList<>(); Stream stream = list.stream(); Stream stringStream = list.parallelStream(); }
Get the array stream through the static method Stream() in Arrays
@Test public void createStream(){ // 2: Get the array stream through the static method Stream() in Arrays String[] strings = new String[10]; Stream stream1 = Arrays.stream(strings); }
Create a Stream through the static method of() in the Stream class
@Test public void createStream(){ // 3: Through the static method of() in the Stream class Stream stringStream1 = Stream.of("1", "2", "3"); }
Create wireless stream
Why is it called wireless flow? It should be because it is a flow returned by a statement that starts with execution but does not end. It can cycle all the time, so it is called wireless flow
iteration
@Test public void createStream(){ // 4: Create infinite flow // iteration Stream iterate = Stream.iterate(0, x -> x + 2); // Generate 10 values iterate.limit(10).forEach(System.out::println); }
generate
@Test public void createStream(){ // 4: Create infinite flow // generate Stream generate = Stream.generate(Math::random); generate.forEach(System.out::println); }
Intermediate operation
An intermediate operation chain that processes the data of the data source
create data source
Add two annotations to the Person entity class
@AllArgsConstructor @NoArgsConstructor
create data source
List personList = Arrays.asList( new Person("Zhang San",18), new Person("Li Si",22), new Person("Wang Wu",27), new Person("Zhao Liu",31), new Person("Apocalypse",50) );
Multiple intermediate operations can be linked to form a pipeline. Unless the termination operation is triggered on the pipeline, the intermediate operation will not perform any processing, but all processing at one time when the operation is terminated is called "lazy evaluation"
Screening and slicing
filter
Filter (predict P) - receives Lambda and excludes some elements from the stream
@Test public void test2(){ // Filter people older than 30 personList.stream().filter(x -> x.getAge() > 30).forEach(System.out::println); }

limit
limit(long maxSize) - truncates the stream so that its elements do not exceed the given number
@Test public void test3(){ // Get two people personList.stream().limit(2).forEach(System.out::println); }

skip
skip(n) - skip elements and return a stream that discards the first N elements. If there are less than N elements in the stream, an empty stream is returned, which is complementary to limit(n)
@Test public void test4(){ // Get the last two digits older than 18 personList.stream().filter(x -> x.getAge() > 18).skip(2).forEach(System.out::println); }

distinct
distinct() - filter to remove duplicate elements through hashcode() and equals() of the elements generated by the stream
Modify data source add duplicate data
List personList = Arrays.asList( new Person("Zhang San",18), new Person("Zhang San",18), new Person("Zhang San",18), new Person("Li Si",22), new Person("Wang Wu",27), new Person("Zhao Liu",31), new Person("Apocalypse",50) );
@Test public void test5(){ // De duplication / / if duplicates are not removed, Equals and HashCode can be rewritten personList.stream().distinct().forEach(System.out::println); }

mapping
map
map - receive Lambda, convert elements into other forms or extract information, and receive a function as a parameter. The function will be applied to each element and mapped to a new element
@Test public void test6(){ List list = Arrays.asList("a", "b", "c", "d"); // Convert all to uppercase list.stream().map(String::toUpperCase).forEach(System.out::println); }

flatmap
flatmap - takes a function as an argument, replaces each value in the stream with another stream, and then links all streams into one stream
@Test public void test7(){ List list = Arrays.asList("aaa","bbb","ccc","ddd"); // Stream<Stream> streamStream = list.stream().map(TestStreamApi::stringToCharacter); // Expected to return a stream, so it will cause a nested stream structure // streamStream.forEach(s -> { // s.forEach(System.out::println); // }); // At this time, you can use flatmap to integrate all streams into one stream list.stream().flatMap(TestStreamApi::stringToCharacter).forEach(System.out::println); }

sort
sorted - natural sort
sorted() - natural sort
@Test public void test8(){ List list = Arrays.asList("c", "f", "a", "d", "b"); // Natural sorting list.stream().sorted().forEach(System.out::println); }

sorted - custom sort
sorted(Comparator c) - custom sorting
@Test public void test9(){ personList.stream().sorted(((o1, o2) -> { if(o1.getAge().equals(o2.getAge())){ return o1.getName().compareTo(o2.getName()); } return o1.getAge().compareTo(o2.getAge()); })).forEach(System.out::println); }

Terminate operation (terminal operation)
A termination operation that executes an intermediate chain of operations and produces results

Find and match
allMatch - checks whether all elements are matched
anyMatch - checks if at least one element is matched
noneMatch - checks if all elements are not matched
findFirst - returns the first element
findAny - returns any element in the current stream
count - returns the total number of elements in the stream
max - returns the maximum value in the stream
min - returns the minimum value in the stream
@Test public void test10() { // Are they all 18 years old boolean b = personList.stream().allMatch(e -> e.getAge().equals(18)); System.out.println("is all match: " + b); // Is anyone 18 boolean b1 = personList.stream().anyMatch(e -> e.getAge().equals(18)); System.out.println("is any match: " + b1); // Is there anyone 18 boolean b2 = personList.stream().noneMatch(e -> e.getAge().equals(18)); System.out.println("is none match: " + b2); // Get the youngest person Optional first = personList.stream().sorted(Comparator.comparingInt(Person::getAge)).findFirst(); System.out.println("first age is: " + first.get()); // Look for anyone from a crowd of 18 years old Optional any = personList.stream().filter(s -> s.getAge().equals(18)).findAny(); System.out.println("age 18 is: " + any.get()); // Get total long count = personList.stream().count(); System.out.println("count num is:" + count); // Get the oldest person Optional max = personList.stream().max(Comparator.comparingInt(Person::getAge)); System.out.println("age max is: " + max); // Get the youngest person Optional min = personList.stream().min(Comparator.comparingInt(Person::getAge)); System.out.println("age min is:" + min); }

reduction
reduce(T identity,BinaryOperator) / reduce(BinaryOperator) - Elements in the flow can be combined repeatedly to obtain a value
@Test public void test11(){ // Calculate array sum List integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Integer reduce = integers.stream().reduce(0, Integer::sum); System.out.println(reduce); // Calculate the total age of personnel Optional reduce1 = personList.stream().map(Person::getAge).reduce(Integer::sum); System.out.println("person age count is : "+reduce1.get()); }

collect
collect - converts the Stream into other forms, receives the implementation of a Collector interface, and is used to summarize the elements in the Stream
@Test public void test12(){ // Collect the names of all personnel and convert them to List List collect = personList.stream().map(Person::getName).collect(Collectors.toList()); System.out.println(" name list is : "+collect); // Collect the names of all personnel and convert them to Set Set collect1 = personList.stream().map(Person::getName).collect(Collectors.toSet()); // Collect the names of all personnel and convert them to HashSet HashSet collect2 = personList.stream().map(Person::getName).collect(Collectors.toCollection(HashSet::new)); // Get total Long collect3 = personList.stream().collect(Collectors.counting()); System.out.println("counting is : "+collect3); // Get average age of personnel from Double collect4 = personList.stream().collect(Collectors.averagingInt(Person::getAge)); System.out.println("avg is :" + collect4); // Get the total age of all personnel Integer collect5 = personList.stream().collect(Collectors.summingInt(Person::getAge)); System.out.println("sum is : " + collect5); // Get the oldest Optional collect6 = personList.stream().collect(Collectors.maxBy((x, y) -> Integer.compare(x.getAge(), y.getAge()))); System.out.println("max by is : "+collect6); // Get minimum age Optional collect7 = personList.stream().map(Person::getAge).collect(Collectors.minBy(Integer::compare)); System.out.println("age min is:" + collect7); // Grouped by age Map<Integer, List> collect8 = personList.stream().collect(Collectors.groupingBy(Person::getAge)); System.out.println("grouping by is:"+collect8); // Multilevel grouping Map<String, Map<String, List>> collect9 = personList.stream().collect(Collectors.groupingBy(Person::getName, Collectors.groupingBy(Person::getName))); System.out.println("Multilevel grouping:"+collect9); // Conditional partition Map<Boolean, List> collect10 = personList.stream().collect(Collectors.partitioningBy(x -> x.getAge() > 25)); System.out.println("partitioningBy is:"+collect10); // Multilevel partition Map<Boolean, Map<Boolean, List>> collect11 = personList.stream().collect(Collectors.partitioningBy(x -> x.getAge() > 25, Collectors.partitioningBy(y -> y.getName().equals("Zhang San")))); System.out.println("Multilevel partition:"+collect11); // Gets the numeric calculation container class IntSummaryStatistics collect12 = personList.stream().collect(Collectors.summarizingInt(Person::getAge)); System.out.println(collect12.getMax()); System.out.println(collect12.getSum()); System.out.println(collect12.getAverage()); System.out.println(collect12.getMin()); System.out.println(collect12.getCount()); // Link owner's name by underline String collect13 = personList.stream().map(Person::getName).collect(Collectors.joining("-")); System.out.println("names is :" + collect13); }
name list is : [Zhang San, Zhang San, Zhang San, Li Si, Wang Wu, Zhao Liu, Apocalypse] counting is : 7 avg is :26.285714285714285 sum is : 184 max by is : Optional[Person(name=Apocalypse, age=50)] age min is:Optional[18] grouping by is:{50=[Person(name=Apocalypse, age=50)], 18=[Person(name=Zhang San, age=18), Person(name=Zhang San, age=18), Person(name=Zhang San, age=18)], 22=[Person(name=Li Si, age=22)], 27=[Person(name=Wang Wu, age=27)], 31=[Person(name=Zhao Liu, age=31)]} Multilevel grouping:{Li Si={Li Si=[Person(name=Li Si, age=22)]}, Zhang San={Zhang San=[Person(name=Zhang San, age=18), Person(name=Zhang San, age=18), Person(name=Zhang San, age=18)]}, Wang Wu={Wang Wu=[Person(name=Wang Wu, age=27)]}, Zhao Liu={Zhao Liu=[Person(name=Zhao Liu, age=31)]}, Apocalypse={Apocalypse=[Person(name=Apocalypse, age=50)]}} partitioningBy is:{false=[Person(name=Zhang San, age=18), Person(name=Zhang San, age=18), Person(name=Zhang San, age=18), Person(name=Li Si, age=22)], true=[Person(name=Wang Wu, age=27), Person(name=Zhao Liu, age=31), Person(name=Apocalypse, age=50)]} Multilevel partition:{false={false=[Person(name=Li Si, age=22)], true=[Person(name=Zhang San, age=18), Person(name=Zhang San, age=18), Person(name=Zhang San, age=18)]}, true={false=[Person(name=Wang Wu, age=27), Person(name=Zhao Liu, age=31), Person(name=Apocalypse, age=50)], true=[]}} 50 184 26.285714285714285 18 7 names is :Zhang San-Zhang San-Zhang San-Li Si-Wang Wu-Zhao Liu-Apocalypse
Parallel flow and sequential flow
Parallel flow is to divide a content into multiple data blocks and process each data block with different threads
Parallel is optimized in Java 8. We can easily operate data in parallel. The Stream API can declaratively switch between parallel flow and sequential flow through parallel() and sequential()
Sequential flow calculates the sum of 100 billion
@Test public void test13(){ Instant now = Instant.now(); long reduce = LongStream.rangeClosed(0, 100000000000L) .reduce(0, Long::sum); System.out.println(reduce); Instant end = Instant.now(); System.out.println("time consuming:"+Duration.between(now,end).toMillis()); }
CPU utilization

Execution time ms
932356074711512064 time consuming:50036
The sum of 100 billion in parallel stream computing
@Test public void test14(){ Instant now = Instant.now(); long reduce = LongStream.rangeClosed(0, 100000000000L) .parallel() .reduce(0, Long::sum); System.out.println(reduce); Instant end = Instant.now(); System.out.println("time consuming:"+Duration.between(now,end).toMillis()); }
CPU utilization

Execution time ms
932356074711512064 time consuming:20068
Switching method
sequential() switches to sequential flow
parallel() switches to parallel flow
Optional class
brief introduction
The optional class (java.util.Optional) is a container class that represents the existence or non existence of a value. Originally, null was used to indicate that a value does not exist. Now optional can better express this concept and avoid null pointer exceptions
common method
of
Optional. Of (T) - create an instance of optional
@Test public void test1(){ // Create a person Optional person = Optional.of(new Person()); // Get the value in Person person1 = person.get(); System.out.println("get method : " + person1); }
get method : Person(name=null, age=null)
empty
Optional.empty() - create an empty optional instance
@Test public void test2(){ Optional<Object> empty = Optional.empty(); System.out.println(empty); }
ofNullable
Optional. Ofnullable (T) - create an optional instance if t is not null, otherwise create an empty instance
@Test public void test3(){ Optional<Object> empty = Optional.ofNullable(null); System.out.println(empty); Optional<Object> empty1 = Optional.ofNullable(new Person()); System.out.println(empty1); }
isPresent
isPresent() - judge whether to include a value
@Test public void test4(){ Optional<Object> empty = Optional.ofNullable(null); System.out.println(empty.isPresent()); Optional<Object> empty1 = Optional.ofNullable(new Person()); System.out.println(empty1.isPresent()); }
orElse
Orelse (T) - returns the value if the calling object contains a value, otherwise returns t
@Test public void test5(){ Optional<Object> empty = Optional.ofNullable(null); System.out.println(empty.orElse("this is null")); Optional<Object> empty1 = Optional.ofNullable(new Person()); System.out.println(empty1.orElse("this is null")); }
orElseGet
orElseGet(Supplier s) - returns the value if the calling object contains a value, otherwise returns the value obtained by S
@Test public void test6(){ Optional<Object> empty = Optional.ofNullable(null); System.out.println(empty.orElseGet(Person::new)); }
map
map(Function f) - if there is a value, process it and return the processed Optional. Otherwise, return Optional empty
@Test public void test7(){ Optional empty = Optional.of(new Person("lisa", 18)); Optional s = empty.map(Person::getName); System.out.println(s.get()); }
lisa
flatMap
flatMap(Function mapper) - similar to Map, the return value must be Optional
@Test public void test8(){ Optional empty = Optional.of(new Person("lisa", 18)); Optional s = empty.flatMap(e -> Optional.of(e.getName())); System.out.println(s.get()); }