How does Stream in Java work?Case Details

Be careful:

  • Stream does not store elements by itself.
  • Stream does not change the source object.Instead, it returns a new Stream with the result
  • Stream operations are delayed, meaning they will not execute until a result is needed.(Delayed Loading)
    Additionally, note that you will inevitably encounter a variety of problems during your advanced Java learning process.For this, I built a skirt 783802103, in which many architects communicate with each other, so don't go in without a foundation!

Stream operation steps

  1. Stream creation: a data source (collection, array) to get a stream.
  2. Stream Intermediate Operation: An intermediate operation chain that processes data from a data source.
  3. Stream termination operation: A termination operation that performs an intermediate chain of operations and produces results.

2 Stream Usage

2.1 Create Stream

//1. Pass Collection.stream() / parallelStream() Create Stream
List<String> list = new ArrayList<String>();
Stream<String> stream11 = list.stream();             // Serial Stream
Stream<String> stream12 = list.parallelStream();     // Parallel Flow

//2. Pass Arrays.stream() Get the array stream
IntStream stream2 = Arrays.stream(new int[]{1,2});  // Serial Stream

//3. Pass Stream.of() Get stream
Stream<String> stream3 = Stream.of("123", "456");    // Serial Stream

//4. To create an infinite flow, you need to cooperate with limit() truncation or continue indefinitely
Stream<Integer> stream41 = Stream.iterate(2, (x) -> x * 2);   // Serial Stream
Stream<Double> stream42 = Stream.generate(Math::random);      // Serial Stream

2.2 Stream Intermediate Operation

Multiple intermediate operations can be connected to form a pipeline, and no intermediate operation will perform any processing unless termination is triggered on the pipeline.Terminating all operations at once is called'delayed Loading'

Intermediate operations (examples) Explain
limit(long maxSize) Truncate so that its elements do not exceed a given number
filter(Predicate<T> predicate) Filter, filter out the desired elements from the stream
skip(long n) Ignore, skip the first n elements, and return null if there are fewer than n elements in the stream
distinct() Removing duplicate elements by elements hashCode() and equals()
map(Funcation<T,R> mapper) Mapping, the function is applied to each element and mapped to a new element
flatMap(Function<T, Stream> mapper) Mapping, converting each value in a stream into a stream, then joining all streams into one stream
sorted() Sort, natural sort
sorted(Comparator<T> comparator) Sort, Custom Sort
// Intermediate operation: No operation will be performed
Stream<Double> stream = Stream.generate(Math::random)   // double infinite flow
.limit(20)                                      // Truncate, Top 20
.filter(x -> x > 0.3)                           // Filter, take more than 0.3 elements
.skip(1)                                        // Ignore, discard the first element
.distinct()                                     // Duplicate removal
.map(x -> x * 10)                               // Mapping, expanding each element 10 times
.sorted();                                      // Sorting double streams

// Terminate operation, only the termination operation will execute all.That is, delayed loading
stream.forEach(System.out::println);
// Intermediate operation: flatMap takes a function as a parameter, swaps each value in the stream into a stream, and then joins all streams into a stream
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
list.stream().flatMap((e) -> filterCharacter(e)).forEach(System.out::println);

//This is required if map is used
list.stream().map((e) -> filterCharacter(e)).forEach((e) -> {
    e.forEach(System.out::println);
});

public Stream<Character> filterCharacter(String str){
    List<Character> list = new ArrayList<>();
    for (Character ch : str.toCharArray()) {
        list.add(ch);
    }
    return list.stream();
}

2.3 Stream terminate operation

2.3.1 Find and Match

Actions (examples) Explain
allMatch(Predicate<T> predicate) Check if all elements match
anyMatch(Predicate<T> predicate) Check if all elements match at least
noneMatch(Predicate<T> predicate) Check if not all elements match
findFirst() Return the first element
findAny() Returns any element in the current stream
count() Returns the total number of elements in the stream
max(Comparator<T> comparator) Returns the maximum value in the stream
min(Comparator<T> comparator) Returns the minimum value in the stream

2.3.2 Protocol - Combines elements in a stream and returns a value

Actions (examples) Explain
reduce(T identitty´╝îBinaryOperator<T>) You need to pass in a starting value, then a binary operation
reduce(BinaryOperator<T>) There is no starting value, and it is possible that the result is empty, so the returned value is encapsulated in Optional
// Summation
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream().reduce(0, (x, y) -> x + y);

// Sum, without a starting value, it is possible that the result is empty, so the returned value is encapsulated in Optional
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Optional<Integer> sum = list.stream().reduce(Integer :: sum);

2.3.3 Collection

Converts a stream to another form.Receives an implementation of the Collector interface for summarizing elements in Stream.The implementation of the Collector interface method determines how streams are collected (for example, to List, Set, Map).However, the Collectors utility class provides many static methods for easily creating common collector instances.

Actions (examples) Explain
Collectors.toList() Convert Stream to List
Collectors.toSet() Convert Stream to Set
Collectors.toCollection(Supplier<T> supplier) Converting streams to other types of collections
Collectors.counting() Number of elements
Collectors.averagingInt/Long/Double(Function<T,R> function) Average, except that the parameter types passed in are different and the return values are Double
Collectors.summingInt/Long/Double(Function<T,R> function) Sum, the difference is that the type of parameter passed in is different, the return value is Integer, Double, Long
Collectors.maxBy(Comparator<T> comparator) Maximum
Collectors.minBy(Comparator<T> comparator) minimum value
Collectors.groupingBy(Function<T,R> function) Grouping, returning to Map
Collectors.partitioningBy(Predicate<T> predicate) Partition, the incoming function returns true and false divided into two zones, returning Map

3 Parallel Flow

Parallel streaming is the process of dividing a content into blocks of data and using different threads to process each block of data separately.Parallel streams are optimized in Java8 so that we can easily manipulate data in parallel.The Stream API can declaratively switch between parallel and sequential streams through parallel () and scqucntial ().

3.1 Fork-Join Framework

Fork-Join framework: java7 provides a framework for performing tasks, that is, if necessary, splitting a large task into several small tasks (which can no longer be split), and then summarizing the results of one small task operation into a join.

The ExecutorService interface is a concrete implementation of the Fork-Join framework to help better leverage the benefits of multiprocessors.It is designed for types of work that can be recursively split into subtasks.The goal is to be able to use all available computing power to improve the performance of your application.(

See this article on how Fork-Join works: illustrating Fork/Join https://mp.weixin.qq.com/s/OzZFGW_8GBYHUa0Ef10WVg

/**
 * To use Fark-Join, the class must inherit RecursiveAction (no return value) or RecursiveTask (with return value)
 *
 * Calculate the number accumulation from start to end
 */
public class ForkJoin extends RecursiveTask<Long> {

    private long start; // Starting Number
    private long end;   // End Number

    public ForkJoin(long start, long end) {
        this.start = start;
        this.end = end;
    }

    // Minimum interval for splitting
    private static final long THRESHOLD = 10000L;

    @Override
    protected Long compute() {
        // When the interval is less than the minimum interval, direct calculation of the accumulation
        if (end - start <= THRESHOLD) {
            long sum = 0;
            for (long i = start; i < end; i++) {
                sum += i;
            }
            return sum;
        } else { // Otherwise, divide the interval into two and divide it into two different threads to calculate
            // Notice here that if there's a problem, it throwsJava.lang.NoClassDefFoundError: Can not initialize classJava.util.concurrent.Locks.AbstractQueuedSynchronizer$Node exception
            long middle = start + (end - start) / 2;

            ForkJoin left = new ForkJoin(start, middle);    // Recursive until the minimum interval is resolved
            left.fork();    // Split Molecular Task, Push into Thread Queue

            ForkJoin right = new ForkJoin(middle, end);     // Recursive until the minimum interval is resolved
            right.fork();   // Split Molecular Task, Push into Thread Queue

            // Value calculated by combining two parts
            return left.join() + right.join();
        }
    }

    public static void main(String[] args) {
        // start time
        Instant start = Instant.now();

        // Thread pool support is required here
        ForkJoinPool pool = new ForkJoinPool();

        // Add up to 100 million
        ForkJoinTask<Long> task = new ForkJoin(0, 100000000L);

        long sum = pool.invoke(task);

        // End time
        Instant end = Instant.now();

        System.out.println(String.format("The cumulative computation time to 100 million is:%s Milliseconds, value:%s", Duration.between(start, end).toMillis(), sum));
    }
}

3.2 Simplification of Fork-Join by Parallel Streams

//start time
Instant start = Instant.now();

long sum = LongStream.rangeClosed(0, 1000000000L)  // Create 0-100 million digital serial streams
	.parallel()                                 // Convert to parallel stream using Fort-Join framework, default ForkJoinPool.commonPool() Thread pool
	.reduce(0, Long :: sum);        // Protocol Calculates the Accumulation of All Elements

//End time
Instant end = Instant.now();
System.out.println(String.format("The cumulative computation time to 100 million is:%s Milliseconds, value:%s", Duration.between(start, end).toMillis(), sum));

3.3 Performance of Parallel Streaming

For performance testing, see Stream Performance https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/8-Stream%20Performance.md The conclusion is quoted here:

*For simple operations, such as the simplest traversal, the Stream Serial API performs significantly worse than the Display Iteration, but the Stream API on the line can be multicore.
*For complex operations, the Stream Serial API performance can match that achieved manually, and the Stream API performance is much better than that achieved manually when executed in parallel.

So if for performance reasons,
1. Manual implementation using external iteration is recommended for simple operations.
2. For complex operations, the Stream API is recommended. 
3. In multicore scenarios, the parallel Stream API is recommended to take advantage of multicore.
4. Parallel Stream API is not recommended for single-core scenarios.

For code simplicity, you can write shorter code using the Stream API.
Even in terms of performance, there is another advantage to using the Stream API whenever possible.
That is, as long as the Java Stream class library is optimized for upgrade, the code can benefit from the upgrade without any modifications.

Finally, note that you will inevitably encounter a variety of problems during your advanced Java learning process.For this, I built a skirt 783802103, in which many architects communicate with each other, so don't go in without a foundation!
The text and pictures in this article are from the Internet plus your own ideas. They are for learning and communication purposes only. They do not have any commercial use. Copyright is owned by the original author. If you have any questions, please contact us in time for processing.

Tags: Java less github

Posted on Sat, 23 May 2020 02:27:51 -0400 by Skor