Understanding Stream streams in Java

Understanding Stream streams in Java

Stream is added to java8. From the word "stream", it seems to be similar to java There is some relationship between InputStream and OutputStream under the IO package. Actually, it doesn't matter. The stream added in Java 8 is to liberate the productivity of programmers when operating collections. A large part of the reason for the liberation can be attributed to the simultaneous Lambda expressions, which greatly improve the programming efficiency and program readability

What is Stream?

Stream It is like an advanced iterator, but it can only be traversed once, like a river flowing eastward; In the process of streaming, the elements in the stream perform some operations, such as "filter out strings with a length greater than 10", "get the first letter of each string", etc.

To manipulate a flow, you first need to have a data source, which can be an array or a collection. Each operation will return a new flow object to facilitate chain operation, but the original flow object will remain unchanged.

There are two types of stream operations:
1) There can be multiple intermediate operations. Each time a new stream is returned, chain operations can be performed.

2) There can only be one terminal operation. After each execution, this stream will be used up. The next operation cannot be performed, so it can only be placed last.
Let's take an example

List<String> list = new ArrayList<>();
list.add("Jiangnan Feipeng");
list.add("Jiangnan Feipeng");

long count = list.stream().distinct().count();

The distinct() method is an intermediate operation (de duplication) that returns a new stream (with no common elements).
The count() method is a terminal operation that returns the number of elements in the stream.

The intermediate operation will not be executed immediately. Only when the terminal operation is performed, the flow starts to traverse truly for mapping, filtering, etc. Generally speaking, it means that multiple operations are performed in a single traverse, and the performance is greatly improved.

1. create a stream
If it is an array, you can use arrays stream() or stream Of() create a stream; If it is a Collection, you can directly use the stream () method to create a stream, because this method has been added to the Collection interface.

        String[] arr = new String[]{"Jiangnan", "Feipeng", "Jiangnan Feipeng"};
        Stream<String> stream = Arrays.stream(arr);

        stream = Stream.of("Jiangnan", "Feipeng", "Jiangnan Feipeng");

        List<String> list = new ArrayList<>();
        list.add("Jiangnan Feipeng");
        stream = list.stream();

If you check the stream source code, you will find that the of() method actually calls arrays Stream() method.

public static<T> Stream<T> of(T... values) {
    return Arrays.stream(values);

In addition, collections can also call the parallelStream() method to create concurrent streams. By default, forkjoinpool Commonpool() thread pool.

List<Long> aList = new ArrayList<>();
Stream<Long> parallelStream = aList.parallelStream();

2. operation flow
Stream class provides many useful methods for operating streams. Here are some common methods

1) Filtering
The filter() method can filter out the elements we want from the stream.

List<String> list = new ArrayList<>();
        list.add("Jiangnan Feipeng");
        list.add("Feipeng Jiangnan");
        Stream<String> stream = list.stream().filter(element -> element.contains("Peng"));

The filter() method receives a parameter of type predict (a new functional interface in Java 8 that accepts an input parameter and returns a boolean result). Therefore, we can directly pass a Lambda expression to the method, such as element - > element Contains is to filter out the string with "Peng".

The forEach() method receives a parameter of type Consumer (a newly added functional interface in Java 8, which accepts an input parameter and no return operation). Class name:: method name is a new syntax introduced in Java 8, system Out returns the PrintStream class and the println method. You should know that it is printed.

Stream Foreach (system.out:: println); It is equivalent to printing in a for loop, similar to the following code:

for (String s : strs) {

Output results:

2) Mapping
If you want to convert elements in a stream into elements in a new stream through some operation, you can use the map() method.

 List<String> list = new ArrayList<>();
        list.add("Jiangnan Feipeng");
        list.add("Feipeng Jiangnan");
        Stream<Integer> stream = list.stream().map(String::length);

The map() method receives a Function (a new functional interface in Java 8, which accepts an input parameter T and returns a result R) type parameter. At this time, the parameter is the length method of the String class, that is, the flow of a Stream into a Stream.

The results of the program output are as follows:

3) Match
The Stream class provides three methods for element matching:
anyMatch(), as long as there is an element matching the passed in condition, it returns true.

allMatch(), if only one element does not match the passed in condition, false is returned; Returns true if all match.

noneMatch(), as long as one element matches the incoming condition, it returns false; Returns true if all match.

List<String> list = new ArrayList<>();
        list.add("Jiangnan Feipeng");
        list.add("Feipeng Jiangnan");
        boolean  anyMatchFlag = list.stream().anyMatch(element -> element.contains("Peng"));
        boolean  allMatchFlag = list.stream().allMatch(element -> element.length() > 1);
        boolean  noneMatchFlag = list.stream().noneMatch(element -> element.endsWith("Friend"));

Because "Jiangnan Feipeng" begins with "Peng", anyMatchFlag should be true; Because the length of all strings is greater than 1, allMatchFlag is true; Because none of the four strings ends with "friend", the noneMatchFlag is true.
The results of the program output are as follows

4) Combination
The main function of the reduce() method is to combine the elements in the Stream. It has two uses:

Optionalreduce(BinaryOperatoraccumulator)  There is no starting value but only one parameter, that is, the operation rule. In this case, the Optional. 
T reduce(T identity, BinaryOperatoraccumulator) There are starting values, operation rules and two parameters. At this time, the returned type is the same as the starting value type.

Take the following example

Integer[] ints = {0, 1, 2, 3};
        List<Integer> list = Arrays.asList(ints);

        Optional<Integer> optional = list.stream().reduce((a, b) -> a + b);
        Optional<Integer> optional1 = list.stream().reduce(Integer::sum);

        int reduce = list.stream().reduce(6, (a, b) -> a + b);
        int reduce1 = list.stream().reduce(6, Integer::sum);

The operation rule can be a Lambda expression (such as (a, b) - > A + b) or a class name:: method name (such as Integer::sum)
The results of program operation are as follows:

3. conversion flow
Since you can convert a set or array into a stream, you should also have a corresponding method to convert the stream back - the collect() method meets this requirement.

List<String> list = new ArrayList<>();
        list.add("Jiangnan Feipeng");
        list.add("Jiangnan Feipeng");

        String[] strArray = list.stream().toArray(String[]::new);

        List<Integer> list1 = list.stream().map(String::length).collect(Collectors.toList());
        List<String> list2 = list.stream().collect(Collectors.toCollection(ArrayList::new));

        String str = list.stream().collect(Collectors.joining(", ")).toString();

toArray() method can convert streams into arrays. You may be curious about string[]: new. What is it? Take a look at the source code of the toArray() method.

<A> A[] toArray(IntFunction<A[]> generator);

That is, string[]: new is an IntFunction, a function that can generate the required new array. You can decompile the bytecode to see what it is:

String[] strArray = (String[])list.stream().toArray((x$0) -> {
    return new String[x$0];

That is, it returns an array of strings of a specified length.
When we need to convert a set into another set according to certain rules, we can use the map() method and the collect() method together.

List<Integer> list1 = list.stream().map(String::length).collect(Collectors.toList());

After the stream of the collection is created through the stream() method, it is mapped to a new stream of string length through the map(String:length), and finally converted to a new collection through the collect() method.

Collectors is a tool class for collectors, with a series of collector implementations built in. For example, the toList() method collects elements into a new java Util List; For example, the toCollection() method collects elements into a new java Util In ArrayList; For example, the joining() method collects elements into a string that can be specified with a delimiter.

Take a look at the output of the program:

Whether the Stream stream is very powerful, that's all. I hope it can help you. Welcome to pay attention and comment. Thank you!

Tags: Java Lambda stream

Posted by HUWUWA on Tue, 31 May 2022 03:02:53 +0530