Stream characteristics
1) Do not store elements: elements are traversed and obtained through Spliterator
2) Do not change the source object: return a new Stream holding the result
3) Delayed execution of operations: Execute when results are needed
Stream life cycle
Stream's life cycle: creation --> intermediate operation --> terminal operation (termination operation)
1) create
Collection acquisition: Collection.stream()
Array creation: Arrays.stream(new String[2])
Numeric creation: Stream.of(1,2,3)
Generate: Stream.generate(Supplier<T> s), which belongs to infinite stream and needs to set stop condition
Iteration: Stream.iterate(final T seed, final UnaryOperator<T> f), which belongs to infinite stream and needs to set the stop condition. UnaryOperator inherits Function, the input and output are of the same type, and the input is the output of the previous one.
Connection: Stream.concat(Stream<? extents T> a, Stream<? extents T> b), two Streams are connected together to generate a new Stream.
Stream also provides a Builder method to create, such as: Stream.builder().add(1).add(2).build()
2) Intermediate operation
Intermediate operations are divided into two categories: stateless operations (StatelessOp), stateful operations (StatefulOp)
StatelessOp:filter\map\mapToInt\mapToLong\mapToDouble
\flatMap\flatMapToInt\flatMapToLong\flatMapToDouble\peek
StatefulOp:distinct\sorted\limit\skip
3) Terminal operation
Terminal operations are: ForEachOp, MatchOp, FindOp, ReduceOp and toArray\collect\count
ForEachOp:forEach\forEachOrdered
MatchOp:anyMatch\allMatch\noneMatch
FindOp:findFirst\findAny
ReduceOp:reduce\min\max
Stream execution
1) Sequential flow
Synchronous execution, executed in the current thread, without thread conversion
2) Parallel stream
Asynchronous execution, multi-thread execution of Fork, for example, the number of single thread execution of trySplit in the Spliterator of Collection is 1<<10, and if it is less than 1<<10, it will be executed in the same thread.
FunctionalInterface
Function interface, the mathematical expression is y = f(x), x: input value f: operation y: output result, the input value outputs a result through operation. Other FunctionalInterfaces are variants of the Function interface and are used in different aspects.
For example:
If the input is null, it is the Supplier, and the mathematical expression is y = f()
If the output is null, it is Consumer, and the mathematical expression is f(x)
The output is boolean, which is Predicate, and the mathematical expression is boolean = f(x)
Another example:
The input value becomes two, which is the Bi** class interface
Input x or output y becomes a certain type, which is **To or To** or **To** and other types
Example: Comparator is int = f(x,y), input x and y two values, and output an int type result
Return value>0, then x>y Return value==0, then x==y Return value<0, then x<y
The feature of FunctionalInterface is that there is only one implementation method in the interface, and there can be multiple methods. Except for the unimplemented methods, all others must be modified by default. The purpose is to use it in combination with lambda to write concise statements.
Collector
1) Collection
Collectors.toCollection: Stream to a collection of the specified type
ArrayList<String> result = Stream
.of("1","2","3","4","5","6","7","8","9")
.collect(Collectors.toCollection(ArrayList::new));
Collectors.toConcurrentMap: Stream is converted to ConcurrentMap, which is ConcurrentHashMap
ConcurrentMap<String, String> result1 = Stream
.of("1","2","3","4","5","6","7","8","9")
.collect(Collectors.toConcurrentMap(key -> "key_" + key, value -> "value_" + value));
Collectors.toList: Convert Stream to List, which is ArrayList
List<String> result2 = Stream
.of("1","2","3","4","5","6","7","8","9")
.collect(Collectors.toList());
Collectors.toMap: Stream is converted to Map, which is HashMap
Map<String, String> result3 = Stream
.of("1","2","3","4","5","6","7","8","9")
.collect(Collectors.toMap(key -> "key_" + key, value -> "value_" + value));
Collectors.toSet: Stream is converted to Set, which is HashSet
Set<String> result4 = Stream
.of("1","2","3","4","5","6","7","8","9")
.collect(Collectors.toSet());
2) Statistics
Collectors.summarizingDouble:Stream转成DoubleSummaryStatistics
Collectors.summarizingInt:Stream转成IntSummaryStatistics
Collectors.summarzingLong:Stream转成LongSummaryStatistics
Calculation: mean, number, maximum, minimum, sum, etc.
IntSummaryStatistics result5 = Stream
.of("1","2","3","4","5","6","7","8","9")
.collect(Collectors.summarizingInt(Integer::valueOf));
result5.getAverage();
result5.getCount();
result5.getMax();
result5.getMin();
result5.getSum();
Collectors.summingDouble: Convert Stream to double and calculate the sum
Collectors.summingInt: Convert Stream to int and calculate the sum
Collectors.summingLong: Convert Stream to long and calculate the sum
int result6 = Stream
.of("1","2","3","4","5","6","7","8","9")
.collect(Collectors.summingInt(Integer::valueOf));
Collectors.averagingDouble: Convert Stream to double and calculate the average
Collectors.averagingInt: Convert Stream to double and calculate the average
Collectors.averagingLong: Convert Stream to double and calculate the average
double result7 = Stream
.of("1","2","3","4","5","6","7","8","9")
.collect(Collectors.averagingInt(Integer::valueOf));
Collectors.counting: Convert Stream to long and calculate the number
long result8 = Stream
.of("1","2","3","4","5","6","7","8","9")
.collect(Collectors.counting());
Collectors.maxBy: Convert Stream to Optional, including the maximum value
Collectors.minBy: Convert Stream to Optional, including the minimum value
Optional<String> result9 = Stream
.of("1", "2", "3", "4", "5", "6", "7", "8", "9")
.collect(Collectors.minBy(Comparator.comparingInt(Integer::parseInt)));
3) Grouping\Partitioning
Collectors.groupingBy: Stream is converted into Map, which is HashMap, Key calculation result, and Value is grouped according to the calculation result
Collectors.groupingByConcurrent: Stream is converted to ConcurrentMap, which is ConcurrentHashMap
Collectors.partitioningBy: Stream is converted to Map, which is Partition, Key is true and false, and Value is partitioned according to the assertion result
Map<String, List<String>> result10 = Stream
.of("1", "2", "3", "4", "5", "6", "7", "8", "9")
.collect(Collectors.groupingBy(value -> value));
4) Joining
Collectors.joining: Stream is converted into String, and the middle of the data is separated by a given symbol, and different symbols can be added before and after
String result11 = Stream
.of("1", "2", "3", "4", "5", "6", "7", "8", "9")
.collect(Collectors.joining("-", "前", "后"));
5) reduction
Collectors.reducing: Stream to the corresponding type
String result12 = Stream
.of("1", "2", "3", "4", "5", "6", "7", "8", "9")
.collect(Collectors.reducing("0", (s, s2) -> s + s2));
6) Mapping
Collectors.mapping: Stream is converted to another type, which can be processed again
List<String> result13 = Stream
.of("1", "2", "3", "4", "5", "6", "7", "8", "9")
.collect(Collectors.mapping(value -> value + "_mapping", Collectors.toList()));
7) Collection and reprocessing
Collectors.collectingAndThen: Data can be processed multiple times
List<String> result14 = Stream
.of("1", "2", "3", "4", "5", "6", "7", "8", "9")
.collect(Collectors.collectingAndThen(Collectors.toList(), strings -> {
strings.forEach(System.out::print);
return Arrays.asList("aa", "bb", "cc");
}));
result14.forEach(System.out::print);