It describes the sequence of intermediate operations on Stream, its impact on performance, and how to tune it.

Java8 Stream: Java8 Stream: Java8 Stream

Execute vertically: map and filter

Take a look at the following example, which finds the string “b” in the stream and converts it to uppercase, with the two intermediate operations map and filter and the closing operation forEach.

Stream.of("a"."b"."c"."d"."e")
    .map(str -> {
        System.out.println("map: \t" + str);
        return str.toUpperCase();
    })
    .filter(str -> {
        System.out.println("filter: " + str);
        return str.equals("B");
    })
    .forEach(str -> {
        System.out.println("forEach: " + str);
    });

// Console output
map: 	a
filter: A
map: 	b
filter: B
forEach: B
map: 	c
filter: C
map: 	d
filter: D
map: 	e
filter: E
Copy the code

According to the output, map, filter, and forEach are executed vertically. Map and filter are executed five times, and forEach is executed once.

If we change the order of operations so that the filter method is executed first, we will greatly reduce the number of executions.

Stream.of("a"."b"."c"."d"."e")
    .filter(str -> {
        System.out.println("filter: " + str);
        return str.equals("b");
    })
    .map(str -> {
        System.out.println("map: \t" + str);
        return str.toUpperCase();
    })
    .forEach(str -> {
        System.out.println("forEach: " + str);
    });

// Console output
filter: a
filter: b
map: 	b
forEach: B
filter: c
filter: d
filter: e
Copy the code

The filter is still executed 5 times, the forEach is executed once, but the map is reduced to one, that is, the filter is executed only once. This technique is faster when there are a large number of elements in the Stream.

Horizontal execution: sorted

Next, let’s look at the sorted operation. We put filter before map:

Stream.of("d"."b"."c"."a"."e")
    .sorted((str1, str2) -> {
        System.out.println("sorted: " + str1 + "," + str2);
        return str1.compareTo(str2);
    })
    .filter(str -> {
        System.out.println("filter: " + str);
        return str.equals("b");
    })
    .map(str -> {
        System.out.println("map: \t" + str);
        return str.toUpperCase();
    })
    .forEach(str -> {
        System.out.println("forEach: " + str);
    });

// Console output
sorted: b, d
sorted: c, b
sorted: c, d
sorted: c, b
sorted: a, c
sorted: a, b
sorted: e, c
sorted: e, d
filter: a
filter: b
map: 	b
forEach: B
filter: c
filter: d
filter: e
Copy the code

At this point, it is found that the sorted operation is performed horizontally, sorting all the elements in the stream, and it is executed for a total of 8 times.

Let’s change the order of operations again to try to optimize performance:

Stream.of("d"."b"."c"."a"."e")
    .filter(str -> {
        System.out.println("filter: " + str);
        return str.equals("b");
    })
    .sorted((str1, str2) -> {
        System.out.println("sorted: " + str1 + "," + str2);
        return str1.compareTo(str2);
    })
    .map(str -> {
        System.out.println("map: \t" + str);
        return str.toUpperCase();
    })
    .forEach(str -> {
        System.out.println("forEach: " + str);
    });

// Console output
filter: d
filter: b
filter: c
filter: a
filter: e
map: 	b
forEach: B
Copy the code

This time, the sorted method is not called, because after being filtered by filter, there is only one element left in the stream and no sorting is required.

In addition, sorted has truncation effect on methods that are executed vertically, such as filter and map. In other words, the intermediate operations before sorted need to be completely executed to form a complete Stream, which is given to sorted.

A mixture of

For example, filter out “b” and “d”, uppercase, and sort:

Stream.of("d"."b"."c"."a"."e")
    .filter(str -> {
        System.out.println("filter: " + str);
        return str.equals("b") || str.equals("d");
    })
    .map(str -> {
        System.out.println("map: \t" + str);
        return str.toUpperCase();
    })
    .sorted((str1, str2) -> {
        System.out.println("sorted: " + str1 + "," + str2);
        return str1.compareTo(str2);
    })
    .forEach(str -> {
        System.out.println("forEach: " + str);
    });

// Console output
filter: d
map: 	d
filter: b
map: 	b
filter: c
filter: a
filter: e
sorted: B, D
forEach: B
forEach: D
Copy the code

Because of sorted’s truncation, it executes filter and map vertically, then sorted horizontally, and finally forEach vertically.

summary

When writing a complex chain of Stream methods, you should generally put the filter operation first to reduce the stress of subsequent operations, especially if there are a large number of elements in the Stream.

In addition, you’d better run the above code yourself and see the output. In the next section, we’ll talk about advanced operations on Stream.

Sorted: the Stream. Sorted method. What is the underlying sorting algorithm? Welcome to discuss in the comments section.