Show you the new feature of JDK8 | Stream stream Stream

Posted by NovaHaCker on Sun, 23 Jan 2022 06:02:15 +0100

I believe brother Meng encountered such code when learning:

List<String> list = new ArrayList();
list.stream().forEach(a-> System.out.println(a));

I believe you are the same as me when you see this code for the first time. What is this TM? Can you see that there is a Lambda expression, and what is this stream?

Is there anything like Steam, a game download platform that can play chicken and CSGO? It's far away. The two have nothing to do.

Now let's uncover the secret of stream, Go!

1. Disadvantages of collective data processing

Hey, isn't it about stream? How to talk about the processing data of the collection. Don't worry, let's introduce stream from the disadvantages of collective data processing.

When we need to operate on the elements in the collection, in addition to the necessary addition, deletion and acquisition, the most typical is collection traversal. Let's experience the disadvantages of collecting operation data. The requirements are as follows:

An ArrayList set stores the following data: Zhang Wuji, Zhou Zhiruo, Zhao Min, Zhang Qiang, Zhang Sanfeng.

Requirements:

  1. Get all the people surnamed Zhang
  2. Get a name with a length of 3 words
  3. Print this data
public static void main(String[] args) {

        ArrayList<String> list = new ArrayList<String>();
        Collections.addAll(list,"zhang wuji","Zhou Zhiruo","Zhao Min","Zhang Qiang","Zhang Sanfeng");

        //1. Get all those surnamed Zhang
        ArrayList<String> zhangList = new ArrayList<String>(); //{"Zhang Wuji", "Zhang Qiang", "Zhang Sanfeng"}
        for (String name : list) {
            if(name.startsWith("Zhang")){
                zhangList.add(name);
            }
        }
    
        //2. Get a name with a length of 3 words
        ArrayList<String> threeList = new ArrayList<String>();//{"Zhang Wuji", "Zhang Sanfeng"}
        for (String name : zhangList) {
            if(name.length() == 3){
                threeList.add(name);
            }
        }
    
        //3. Print these data / / {"Zhang Wuji", "Zhang Sanfeng"}
        for (String name : threeList) {
            System.out.println(name);
        }
    }

It can be seen that each requirement needs to traverse the set once and make a new set to load the data, which is very troublesome.

2. Introduction to stream

Stream stream is not a data structure. It does not save data, but processes the data in the collection. The idea of stream flow is similar to the "production line" in a factory workshop.

Note: the Stream stream has nothing to do with the IO Stream (InputStream/OutputStream). Please temporarily forget the inherent impression of the traditional IO Stream


Let's take a look at transforming the above code with the help of Stream flow:

public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        Collections.addAll(list,"zhang wuji","Zhou Zhiruo","Zhao Min","Zhang Qiang","Zhang Sanfeng");
        list.stream()
                .filter((s)->{
                    return s.startsWith("Zhang");
                })
                .filter((s)->{
                    return s.length() == 3;
                })
                .forEach((s)->{
                    System.out.println(s);
                });
    }

3. Two ways to obtain Stream

Getting a stream is very simple. There are two common methods:

  1. All Collection collections can be accessed through stream() method to get the stream
  2. Using the Stream interface of() static method, which can get the Stream
public static void main(String[] args) {
        //Method 1: get the stream according to the Collection
        //There is a default method in the Collection interface: default stream < E > stream ()
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();

        Set<String> set  = new HashSet<>();
        Stream<String> stream2 = set.stream();

        //Method 2: the static method of in Stream obtains the Stream. Application scenario: put the array
        //static<T> Stream<T> of(T... values) {
        Stream<String> stream3 = Stream.of("aa", "bb", "cc");

        String[] strs = {"aa","bb","cc"};
        Stream<String> stream4 = Stream.of(strs);


        //Is an array of basic types OK? This is not possible. The entire array will be operated as an element
        int[] arr = {11,22,33};
        //Here, the type of stream operation is int [], which treats the whole array as an element
        Stream<int[]> stream5 = Stream.of(arr);
    }

4.Stream adoption method and precautions


Termination method: the return value type is no longer a method of Stream type, and chain call is no longer supported. Common termination methods are:

  1. count
  2. foreach
  3. anyMatch & allMatch & noneMatch
  4. findAny & findFirst
  5. reduce
  6. Both Max & min aggregation methods terminate the operation

Non terminating method: also known as function splicing method. The return value type of the value is still a method of Stream type, and chain call is supported (except for terminating methods, both of them and methods are non terminating methods).

Stream considerations

  1. Stream can only be operated once
  2. The Stream method returns a new Stream
  3. Stream does not call the termination method, and the intermediate operation will not be executed
public static void main(String[] args) {
        Stream<String> stream = Stream.of("aa", "bb", "cc");
        //1. Stream can only be operated once
        //long count = stream.count(); // Successful execution
        //long count2 = stream.count();// Execution error

        //2. The stream method returns a new stream
        //Stream<String> limit = stream.limit(1);
        //Two streams are not the same object
        //System.out.println("stream"+stream);
        //System.out.println("limit"+limit);

        //3.Stream does not call the termination method, and the intermediate operation will not be executed
        //Here, the intermediate operation will be executed only when count() (termination method) is called
        stream.filter((s)->{
            System.out.println(s);
            return true;
        }).count();
        
    }

5.Stream API

Stream API allows us to quickly complete many complex operations, such as filtering, slicing, mapping, finding, de duplication, statistics, matching and reduction.

Because there are too many stream APIs, we will only focus on a few common ones.

forEach

forEach is used to traverse the data in the stream.

@Test
public void testForEach(){
    List<String> list  = new ArrayList<>();
    Collections.addAll(list,"Mary","Lucy","James","Johnson","Steve");

    list.stream()
            .forEach((s)->{
                System.out.println(s);
            });
}

count

Count is used to count the number of elements. This method returns a long value representing the number of elements.

@Test
public void testCount(){
    List<String> list  = new ArrayList<>();
    Collections.addAll(list,"Mary","Lucy","James","Johnson","Steve");

    long count = list.stream().count();
    System.out.println(count);  //5

}

filter

Filter is used to filter data and return data that meets the filtering conditions.

@Test
public void testFilter(){
    List<String> list  = new ArrayList<>();
    Collections.addAll(list,"Mary","Lucy","James","Johnson","Steve");

    //Get a person whose name is four words long
    list.stream()
            .filter((s)->{
                return s.length() == 4;
            })
            .forEach((s)->{
                System.out.println(s);
            });
}

map

If you need to map elements in a stream to another stream, you can use the map method.

@Test
public void testMap(){
    Stream<String> original = Stream.of("11", "22", "33");
		
    //Map can convert one type of flow into another type of flow
    //Convert the string summarized by the Stream stream to Integer
    Stream<Integer> integerStream = original.map((s) -> {
        return Integer.parseInt(s);
    });

}

distinct

distinct is used to remove duplicate data in the set.

@Test
public void testDistinct(){
    Stream<Integer> stream = Stream.of(22,33,22,11,33);
    /*stream.distinct()
        .forEach((s)->{
                System.out.println(s);
        });*/
    Stream<String> stream1 = Stream.of("aa", "bb", "aa", "bb", "cc");
    stream1.distinct().forEach(s-> System.out.println(s));
 }

/**
 * distinct Remove duplicates from custom objects (override hashcode and equals, otherwise they will not be duplicated)
 */
@Test
public void testDistinct2(){
      Stream<Person> stream = Stream.of(
             new Person("army officer's hat ornaments", 18),
             new Person("Yang Yuhuan", 20),
             new Person("Yang Yuhuan", 20),
             new Person("Xi Shi", 16),
             new Person("Xi Shi", 16),
             new Person("Wang Zhaojun", 25)
      );
      stream.distinct().forEach(System.out::println);
    }

reduce

If you need to summarize all the data into one data, you can use the reduce method.

@Test
public void testReduce(){
    //T reduce(T identity, BinaryOperator<T> accumulator);
    //T identity: default value
    //Binaryoperator < T > accumulator: the way to process data
    /*Integer reduce = Stream.of(4, 5, 3, 9).reduce(
                0, (x, y) -> {
                    //x=0, y=4
                    //x=4, y=5
                    //x=9, y=3
                    //x=12, y=9
                    System.out.println("x="+x+", y="+y);
                    return x + y;
                }
    );
    System.out.println("reduce="+reduce); //21*/

    //Get maximum
    Integer max = Stream.of(4, 5, 3, 9).reduce(0, (x, y) -> {
        return x > y ? x : y;
    });
    System.out.println("Maximum:"+max);
}

6. Collect the results in the Stream

After the convection operation is completed, if you need to save the results of the stream to data or collection, you can collect the data in the stream.

6.1 collect into collection

The Stream stream provides the collect method, and its parameters need A Java util. Stream. Collector < T, A, R > interface object to specify which collection to collect. java. util. The collectors class provides methods that can be used as instances of the collector interface:

//The list converted here is ArrayList. If you want to convert it to a specific list, you need to use the toCollection method
public static <T> Collector<T,?,List<T>> toList( ): Convert to List aggregate

//The set converted here is a HashSet. If you need to specify a set, you need to use the toCollection method
public static <T> Collector<T,?,List<T>> toSet( ): Convert to Set aggregate
@Test
public void testStreamToCollection(){
    Stream<String> stream = Stream.of("aa", "bb", "cc");
    //Collect data from the stream into a collection
    /*List<String> list = stream.collect(Collectors.toList());
    System.out.println("list = "+list);*/   //list = [aa, bb, cc]

    /*Set<String> set = stream.collect(Collectors.toSet());
    System.out.println("set = "+set);  //set = [aa, bb, cc]*/

    //Collected into the specified collection ArrayList
    //If you want to convert to a specific list, you need to use the toCollection method
    LinkedList<String> collect = stream.collect(Collectors.toCollection(LinkedList::new));
}

6.1 collect into array

//Collect data from the stream into an array
@Test
public void testStreamToArray(){
    Stream<String> stream = Stream.of("aa", "bb", "cc");
    //It is inconvenient to convert to an object array
    Object[] objects = stream.toArray();
    //String[]
    String[] strings = stream.toArray(String[]::new);
    for (String string : strings) {
        System.out.println("string = "+string);
    }
}

Topics: Java stream