Article directory
First, what is Stream?
It is a data channel for manipulating the sequence of elements generated by data sources (collections, arrays, etc.).
The ** stream ** in a collection is about data, and the Stream here is about computing!
Be careful:
-
Stream itself does not store elements.
-
Stream does not change the source object. Instead, they return to a new Stream that holds the results.
-
Stream operations are delayed. This means that they will wait until the results are needed.
2. Three steps of Stream operation
- Create Stream
A data source (such as a collection, an array) to obtain a stream - Intermediate operation
An intermediate operation chain that processes data from data sources - Termination operation (terminal operation)
A termination operation, an intermediate chain of operations, and results
3. Creating Stream
Collection provides two methods stream() and parallelStream()
List<String> list = new ArrayList<>(); Stream<String> stream1 = list.stream(); //Get a sequential stream Stream<String> parallelStream = list.parallelStream(); //Getting a Parallel Flow
2. Get an array stream from stream() in Arrays
Integer[] nums = new Integer[10]; Stream<Integer> stream2 = Arrays.stream(nums);
3. Through the static method of() in Stream class
Using Stream.of(), create a stream by displaying values. It can receive any number of parameters.
Stream<Integer> stream3 = Stream.of(1,2,3,4,5,6);
4. Creating Infinite Flow
You can use the static methods Stream.iterate() and Stream.generate() to create an infinite flow.
//iteration Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2); stream4.limit(10).forEach(System.out::println);
/ / generation
Stream<Double> stream5 = Stream.generate(Math::random).limit(2); stream5.forEach(System.out::println);
IV. Stream's Intermediate Operation
Multiple intermediate operations can be connected to form a pipeline, unless the termination operation is triggered on the pipeline, the intermediate operation will not perform any processing! When terminating the operation, all the processes are disposed of at one time, which is called "inert evaluation".
4.1. Screening and slicing
- filter: Receives Lambda and excludes certain elements from the stream.
- limit: Cut off the stream so that its elements do not exceed a given number.
- Skp (n): Skip the element and return a stream that throws away the first n elements. If there are less than n elements in the flow, an empty flow is returned. Complementarity with limit(n)
- distinct: Screening to remove duplicate elements by hashCode() and equals() of the elements generated by the stream
Example:
public class TestStreamaAPI { List<Employee> emps = Arrays.asList( new Employee(102, "Li Si", 59, 6666.66), new Employee(101, "Zhang San", 18, 9999.99), new Employee(103, "Wang Wu", 28, 3333.33), new Employee(104, "Zhao Liu", 8, 7777.77), new Employee(104, "Zhao Liu", 8, 7777.77), new Employee(104, "Zhao Liu", 8, 7777.77), new Employee(105, "Pseudo-ginseng", 38, 5555.55) ); /* Screening and slicing filter: Receive Lambda and exclude certain elements from the stream. limit: Cut off the flow so that its elements do not exceed a given number. skip(n) : Skip the element and return to a stream that throws away the first n elements. If there are less than n elements in the flow, an empty flow is returned. Complementarity with limit(n) distinct : Screening, removing duplicate elements by hashCode() and equals() of the elements generated by the stream */ //Internal Iteration: Iterative Operation Stream API Internal Completion @Test public void test2(){ //Intermediate operation: no processing is done Stream<Employee> stream = emps.stream() .filter((e) -> { System.out.println("Test Intermediate Operation"); return e.getAge() <= 35; }); //Termination operation: Execute all content at once, called "inert evaluation" stream.forEach(System.out::println); } //External iteration: self-written iteration @Test public void test3(){ Iterator<Employee> it = emps.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } //Only two "short circuits" were printed, not four. @Test public void test4(){ emps.stream() .filter((e) -> { System.out.println("Short circuit!"); // && || return e.getSalary() >= 5000; }).limit(2) .forEach(System.out::println); } //Only two "short circuits" were printed, not four. The difference from test4() is to skip the first two data and take the last two data. @Test public void test5(){ emps.parallelStream() .filter((e) -> e.getSalary() >= 5000) .skip(2) .forEach(System.out::println); } //Employee's hashCode() and equals() must be rewritten, otherwise the de-duplication function will not take effect. @Test public void test6(){ emps.stream() .distinct() .forEach(System.out::println); } }
4.2. Mapping: (emphasis)
map: Receives Lambda, converts elements into other forms or extracts information. Receives a function as a parameter that is applied to each element and mapped to a new element.
flatMap: Receives a function as a parameter, replaces each value in the stream with another stream, and then connects all streams into one stream.
@Test public void test1(){ Stream<String> str = emps.stream() .map((e) -> e.getName()); System.out.println("-------------------------------------------"); List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee"); strList.stream() .map(String::toUpperCase) .forEach(System.out::println); System.out.println("====================================="); //Extract names from Employee emps.stream() .map(Employee::getName) .forEach(System.out::println); System.out.println("====================================="); //The filterCharacter() method returns a stream for each character. Stream<Stream<Character>> stream2 = strList.stream() .map(TestStreamAPI1::filterCharacter);// {{a,a,a},{b,b,b},{c,c,c}} stream2.forEach((sm) -> { sm.forEach(System.out::println); //{a,a,a,b,b,b,c,c,c} }); System.out.println("====================================="); // Stream<Character> stream3 = strList.stream() .flatMap(TestStreamAPI1::filterCharacter); stream3.forEach(System.out::println); } public static Stream<Character> filterCharacter(String str){ List<Character> list = new ArrayList<>(); for (Character ch : str.toCharArray()) { list.add(ch); } return list.stream(); }
4.3. Sort:
- sorted(): Comparable
- sorted(Comparator com): Customized sorting
@Test public void test2(){ //Natural Sorting, by String's built-in Comparable Sorting emps.stream() .map(Employee::getName) .sorted() .forEach(System.out::println); System.out.println("------------------------------------"); //Custom sort emps.stream() .sorted((x, y) -> { if(x.getAge() == y.getAge()){ return x.getName().compareTo(y.getName()); }else{ return Integer.compare(x.getAge(), y.getAge()); } }).forEach(System.out::println); }
V. Termination of Stream
5.1. Finding and Matching
allMatch: Check if all elements match
anyMatch: Check whether at least one element matches
noneMatch: Check if there are no matching elements
findFirst: Returns the first element
findAny: Returns any element in the current stream
count: The total number of elements in the return stream
max: Maximum value in the return stream
min: Minimum value in the return stream
For Each: Internal Iteration
5.2. Reduction: (emphasis)
The elements in the flow are combined repeatedly to get a value.
Reduction (T identity, BinaryOperator) returns a result of T
Reduction (BinaryOperator) returns Optional < T >
@Test public void test1(){ List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10); //The starting value is 0, which is certainly not empty, so the return value is Integer. Integer sum = list.stream() .reduce(0, (x, y) -> x + y); System.out.println(sum); System.out.println("----------------------------------------"); //Because there is no starting value, the return value is Optional Optional<Double> op = emps.stream() .map(Employee::getSalary) .reduce(Double::sum); System.out.println(op.get()); }
5.3. Collection: (emphasis)
Convert the stream to other forms. Receive an implementation of the Collector interface for summarizing elements in Stream.
collect(Collector c)
The implementation of methods in the Collector interface determines how to perform collection operations (such as collecting List s, Set s, Maps) on the convection. But Collectors utility classes provide many static methods to easily create common collector instances
List<Employee> emps = Arrays.asList( new Employee(102, "Li Si", 79, 6666.66, Status.BUSY), new Employee(101, "Zhang San", 18, 9999.99, Status.FREE), new Employee(103, "Wang Wu", 28, 3333.33, Status.VOCATION), new Employee(104, "Zhao Liu", 8, 7777.77, Status.BUSY), new Employee(104, "Zhao Liu", 8, 7777.77, Status.FREE), new Employee(104, "Zhao Liu", 8, 7777.77, Status.FREE), new Employee(105, "Pseudo-ginseng", 38, 5555.55, Status.BUSY) ); @Test public void test4(){ // Maximum value Optional<Double> max = emps.stream() .map(Employee::getSalary) .collect(Collectors.maxBy(Double::compare)); System.out.println(max.get()); //Minimum wage Optional<Employee> op = emps.stream() .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))); System.out.println(op.get()); //The sum of wages Double sum = emps.stream() .collect(Collectors.summingDouble(Employee::getSalary)); System.out.println(sum); //Average wage Double avg = emps.stream() .collect(Collectors.averagingDouble(Employee::getSalary)); System.out.println(avg); // Total Long count = emps.stream() .collect(Collectors.counting()); System.out.println(count); System.out.println("--------------------------------------------"); DoubleSummaryStatistics dss = emps.stream() .collect(Collectors.summarizingDouble(Employee::getSalary)); System.out.println(dss.getMax()); }
5.4, grouping
Collectors.groupingBy();
//Grouping @Test public void test5(){ Map<Status, List<Employee>> map = emps.stream() .collect(Collectors.groupingBy(Employee::getStatus)); System.out.println(map); }
Operation results:
{VOCATION=[Employee [id=103, name=Wang Wu, age=28, salary=3333.33, status=VOCATION]], BUSY=[Employee [id=102, name=Li Si, age=79, salary=6666.66, status=BUSY], Employee [id=104, name=Zhao Liu, age=8, salary=7777.77, status=BUSY], Employee [id=105, name=Pseudo-ginseng, age=38, salary=5555.55, status=BUSY]], FREE=[Employee [id=101, name=Zhang San, age=18, salary=9999.99, status=FREE], Employee [id=104, name=Zhao Liu, age=8, salary=7777.77, status=FREE], Employee [id=104, name=Zhao Liu, age=8, salary=7777.77, status=FREE]]}
Multilevel grouping:
//Multilevel grouping @Test public void test6(){ Map<Status, Map<String, List<Employee>>> map = emps.stream() .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> { if(e.getAge() >= 60) return "old age"; else if(e.getAge() >= 35) return "middle age"; else return "adult"; }))); System.out.println(map); }
Operation results:
{VOCATION={adult=[Employee [id=103, name=Wang Wu, age=28, salary=3333.33, status=VOCATION]]}, FREE={adult=[Employee [id=101, name=Zhang San, age=18, salary=9999.99, status=FREE], Employee [id=104, name=Zhao Liu, age=8, salary=7777.77, status=FREE], Employee [id=104, name=Zhao Liu, age=8, salary=7777.77, status=FREE]]}, BUSY={adult=[Employee [id=104, name=Zhao Liu, age=8, salary=7777.77, status=BUSY]], old age=[Employee [id=102, name=Li Si, age=79, salary=6666.66, status=BUSY]], middle age=[Employee [id=105, name=Pseudo-ginseng, age=38, salary=5555.55, status=BUSY]]}}
5.5, zoning
Collectors.partitioningBy()
@Test public void test7(){ Map<Boolean, List<Employee>> map = emps.stream() .collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000)); System.out.println(map); }
5.6, prefix, suffix
Collectors.joining()
@Test public void test8(){ String str = emps.stream() .map(Employee::getName) .collect(Collectors.joining("," , "----", "----")); System.out.println(str); }