The set of elements to be processed by a Stream is treated as a Stream. During the flow, the Stream API is used to manipulate the elements in the Stream, such as filtering, sorting, aggregating, and so on.

There are roughly two types of Stream operators: the intermediate operator and the terminating operator

Intermediate operator

In the case of a data flow, the intermediate operator can execute the specified handler, and the data flow can still be passed to the operator at the next level.

There are eight intermediate operators (excluding parallel and sequential, which do not involve processing streams of data) :

  1. Map (mapToInt mapToLong, mapToDouble) conversion operators, such as A – > B, the default here provides an int, long, double operators.
  2. Flatmap (flatmapToInt flatmapToLong, flatmapToDouble) the pat down operations such as int [] {4} 2 pat down into 2 and 4 is one from the original data into three, By default, int,long, and double are provided.
  3. If there are 10 streams in a stream, I can use the first 3 streams.
  4. Distint deduplicating: Deduplicating elements using equals ().
  5. Filter Indicates the operation of filtering unwanted data.
  6. Peek pick out operation, if you want to perform some operation on the data, such as: read, edit, modify, etc.
  7. Skip the operation. Skip some elements.
  8. Sorted (unordered) sorting operation, the sequence of elements, the premise is to implement the Comparable interface, of course, can also customize the comparator.

Terminate operator

After the data is processed, it’s the end operator’s turn;

The terminating operator is used to collect or consume data. Data does not flow down to the terminating operator. The terminating operator can only be used once.

  1. Collect Collects all data. This operation is very important. Official Collectors provide a large number of Collectors.
  2. Count Indicates the number of data to be counted.
  3. FindFirst, findAny, find the first, findAny return type is Optional.
  4. NoneMatch, allMatch, anyMatch: indicates whether there are elements matching the conditions in the data stream. The returned value is bool.
  5. Min and Max operations require custom comparators to return the maximum and minimum values in the data stream.
  6. Reduce reduces the value of the entire data flow to a value. For example, count, min, and Max are reduced.
  7. ForEach, forEachOrdered traversal, where the final data is consumed.
  8. The toArray operation converts the elements of a data stream into an array.

The creation of a Stream

1, through the Java. Util. Collection. Set stream () method is used to create flow

List<String> list = Arrays.asList("a"."b"."c");
// Create a sequential stream
Stream<String> stream = list.stream();
// Create a parallel stream
Stream<String> parallelStream = list.parallelStream();

Copy the code

Create a stream from Arrays using the java.util.arrays.stream (T[] array) method

int[] array= {1.3.5.6.8};
IntStream stream = Arrays.stream(array);

Copy the code

Iterate (), iterate(), generate(), iterate()

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);

Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
stream2.forEach(System.out::println); // 0 3 6 9

Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
stream3.forEach(System.out::println);

Copy the code

Output results:

3
6
9
0.8106623442686114
0.11554643727388458
0.1404645961428974

Process finished with exit code 0

Copy the code

Simple distinction between stream and parallelStream:

Stream is a sequential stream, and the main thread performs operations on the stream in sequence; ParallelStream is a parallelStream that operates internally on streams in a manner that allows multiple threads to execute in parallel, but only if there is no order required for data processing in the stream.

For example, to filter odd numbers in a set, the processing of the two is different:

The Stream to use

Iterating/matching (foreach/find/match)

Stream also supports iterating over and matching elements like collections, but the elements in a Stream are Optional. Stream traversal and matching are very simple.

public class StreamTest {

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(7.6.9.3.8.2.1);
        // Iterate over the elements that output the condition
        list.stream().filter(x -> x > 6).forEach(System.out::println);
        // Match the first one
        Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
        // Match any (for parallel streams)
        Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
        // Whether to include elements that meet certain conditions
        boolean anyMatch = list.stream().anyMatch(x -> x < 6);
        System.out.println("Match the first value:" + findFirst.get());
        System.out.println("Match any value:" + findAny.get());
        System.out.println("Is there a value greater than 6?"+ anyMatch); }}Copy the code

Output results:

7
9
8Match the first value:7To match any value:8Is there a greater than6Value:true

Process finished with exit code 0

Copy the code

Filter

Filtering is an operation that verifies the elements in the flow according to certain rules and extracts the elements that meet the conditions into the new flow.

selectIntegerAll the elements greater than 7 in the set, and print them out

public class StreamTest {

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(6.7.3.8.1.2.9);
        Stream<Integer> stream = list.stream();
        stream.filter(x -> x > 7).forEach(System.out::println); }}Copy the code

Output results:

8
9

Process finished with exit code 0

Copy the code

Polymerization (Max/min/count)

The words Max, min, and count are familiar to you, yes, we use them for data statistics in mysql. Java Stream also introduces these concepts and usage, greatly facilitates our collection, array data statistics work.

Case 1: AcquisitionStringThe longest element in the set.

public class StreamTest {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("adnm"."admmt"."pot"."xbangd"."weoujgsd");
        Optional<String> max = list.stream().max(Comparator.comparing(String::length));
        System.out.println("Longest string:"+ max.get()); }}Copy the code

Output results:

Longest string: weoujgSD Process Finished with exit code 0Copy the code

Case 2: AcquisitionIntegerThe maximum value in the set.

public class StreamTest {

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(7.6.9.4.11.6);
        // Natural ordering
        Optional<Integer> max = list.stream().max(Integer::compareTo);
        // Custom sort
        Optional<Integer> max2 = list.stream().max(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                returno1.compareTo(o2); }}); System.out.println("Maximum natural ordering:" + max.get());
        System.out.println("Maximum value of a custom sort:"+ max2.get()); }}Copy the code

Output results:

Maximum natural ordering:11The maximum value of a custom sort:11

Process finished with exit code 0

Copy the code

Case 3: CalculationIntegerThe number of elements greater than 6 in a set.

public class StreamTest {

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(7.6.4.8.2.11.9);
        long count = list.stream().filter(x -> x > 6).count();
        System.out.println("Number of elements greater than 6 in list:"+ count); }}Copy the code

Output results:

listIn more than6The number of elements in4

Process finished with exit code 0

Copy the code

Mapping (map/flatMap)

Mapping, which maps elements of one stream to another according to certain mapping rules. There are map and flatMap:

  • map: takes a function as an argument that is applied to each element and mapped to a new element.
  • flatMap: Takes a function as a parameter, replaces each value in the stream with another, and concatenates all streams into one.

Example 1: Change all elements of an English string array to uppercase. Each element of an integer array is plus 3.

public class StreamTest {

    public static void main(String[] args) {
        String[] strArr = { "abcd"."bcdd"."defde"."fTr" };
        List<String> strList = Arrays.stream(strArr).map(String::toUpperCase).collect(Collectors.toList());
        System.out.println(Capitalize each element: + strList);
        List<Integer> intList = Arrays.asList(1.3.5.7.9.11);
        List<Integer> intListNew = intList.stream().map(x -> x + 3).collect(Collectors.toList());
        System.out.println("+3 per element:"+ intListNew); }}Copy the code

Output results:

Capitalize each element: [ABCD, BCDD, DEFDE, FTR] + for each element3: [4.6.8.10.12.14]

Process finished with exit code 0

Copy the code

Case 2: Merge two character arrays into a new character array.

public class StreamTest {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("m,k,l,a"."1 hc-positie");
        List<String> listNew = list.stream().flatMap(s -> {
            // Convert each element to a stream
            String[] split = s.split(",");
            Stream<String> s2 = Arrays.stream(split);
            return s2;
        }).collect(Collectors.toList());
        System.out.println("Collection before processing:" + list);
        System.out.println("Processed collection:"+ listNew); }}Copy the code

Output results:

Set before processing: [M, K, L,a,1.3.5.7[m, K, L, a,1.3.5.7]

Process finished with exit code 0

Copy the code

Reduction (reduce)

Reduction, also known as reduction, is the reduction of a stream to a value that enables summing, multiplying, and maximizing the set.

Case 1: begIntegerThe sum, product, and maximum of the elements of a set.

public class StreamTest {

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1.3.2.8.11.4);
        // Summation 1
        Optional<Integer> sum = list.stream().reduce(Integer::sum);
        // Summation 2
        Optional<Integer> sum2 = list.stream().reduce(Integer::sum);
        // Summation 3
        Integer sum3 = list.stream().reduce(0, Integer::sum);
        / / product
        Optional<Integer> product = list.stream().reduce((x, y) -> x * y);
        // Obtain the maximum value in method 1
        Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y);
        // To find the maximum value, write method 2
        Integer max2 = list.stream().reduce(1, Integer::max);
        System.out.println("List sum:" + sum.get() + "," + sum2.get() + "," + sum3);
        System.out.println("List quadrature:" + product.get());
        System.out.println("List sum:" + max.get() + ","+ max2); }}Copy the code

Output results:

listSum:29.29.29
listQuadrature:2112
listSum:11.11

Process finished with exit code 0

Copy the code

The collection (toList/toSet/toMap)

Because streams do not store data, the data in the stream needs to be reassembled into new collections after the data in the stream is processed. ToList, toSet and toMap are more commonly used, in addition to toCollection, toConcurrentMap and other more complex uses.

Here’s an example of toList, toSet, and toMap:

public class Person {

    private String name;  / / name
    private int salary; / / salary
    private int age; / / age
    private String sex; / / gender
    private String area;  / / region

    // The constructor
    public Person(String name, int salary, int age,String sex,String area) {
        this.name = name;
        this.salary = salary;
        this.age = age;
        this.sex = sex;
        this.area = area;
    }

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSalary(a) {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    public int getAge(a) {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex(a) {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getArea(a) {
        return area;
    }

    public void setArea(String area) {
        this.area = area;
    }

    @Override
    public String toString(a) {
        return "Person{" +
                "name='" + name + '\' ' +
                ", salary=" + salary +
                ", age=" + age +
                ", sex='" + sex + '\' ' +
                ", area='" + area + '\' ' +
                '} '; }}Copy the code
public class StreamTest {

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1.6.3.4.6.7.9.6.20);
        List<Integer> listNew = list.stream().filter(x -> x % 2= =0).collect(Collectors.toList());
        Set<Integer> set = list.stream().filter(x -> x % 2= =0).collect(Collectors.toSet());
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom".8900.23."male"."New York"));
        personList.add(new Person("Jack".7000.25."male"."Washington"));
        personList.add(new Person("Lily".7800.21."female"."Washington"));
        personList.add(new Person("Anni".8200.24."female"."New York")); Map<? , Person>map = personList.stream().filter(p -> p.getSalary() > 8000)
                .collect(Collectors.toMap(Person::getName, p -> p));
        System.out.println("toList:" + listNew);
        System.out.println("toSet:" + set);
        System.out.println("toMap:" + map); }}Copy the code

Output results:

toList:[6.4.6.6.20]
toSet:[4.20.6]
toMap:{Tom=Person{name='Tom', salary=8900, age=23, sex='male', area='New York'}, Anni=Person{name='Anni', salary=8200, age=24, sex='female', area='New York'}}

Process finished with exit code 0

Copy the code

Statistics (count/averaging)

Collectors provides a set of static methods for data statistics:

  • Count:count
  • Average:averagingInt,averagingLong,averagingDouble
  • The most value:maxBy,minBy
  • Sum:summingInt,summingLong,summingDouble
  • Statistics all above:summarizingInt,summarizingLong,summarizingDouble

Case: Count the number of employees, average salary, total salary, maximum salary.

public class StreamTest {

    public static void main(String[] args) {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom".8900.23."male"."New York"));
        personList.add(new Person("Jack".7000.25."male"."Washington"));
        personList.add(new Person("Lily".7800.21."female"."Washington"));
        / / the total number
        long count = personList.size();
        // Ask for the average salary
        Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
        // Ask for the highest salary
        Optional<Integer> max = personList.stream().map(Person::getSalary).max(Integer::compare);
        // Sum of wages
        int sum = personList.stream().mapToInt(Person::getSalary).sum();
        // Count all information at once
        DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
        System.out.println("Number of employees:" + count);
        System.out.println("Average salary of employees:" + average);
        System.out.println("Maximum employee salary:" + max.get());
        System.out.println("Total wages of employees:" + sum);
        System.out.println("Employee salary all statistics:"+ collect); }}Copy the code

Output results:

Total employees:3Average employee salary:7900.0Maximum employee salary:8900Total salary of employees:23700All statistics of employee salary: DoubleSummaryStatistics{count=3, sum=23700.000000, min=7000.000000, average=7900.000000, max=8900.000000}

Process finished with exit code 0

Copy the code

Group (partitioningBy/groupingBy)

  • Partition:streamAccording to the condition divided into twoMapFor example, employees are divided into two parts according to whether the salary is higher than 8000.
  • Grouping: Divide the collection into multiple Maps, such as grouping employees by gender. There are single-level grouping and multilevel grouping.

Case: The employee is divided into two parts according to whether the salary is higher than 8000; Group employees by gender and region

public class StreamTest {

    public static void main(String[] args) {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom".8900.23."male"."Washington"));
        personList.add(new Person("Jack".7000.25."male"."Washington"));
        personList.add(new Person("Lily".7800.21."female"."New York"));
        personList.add(new Person("Anni".8200.24."female"."New York"));
        // Group employees according to whether their salary is higher than 8000
        Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
        // Group employees by gender
        Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));
        // Group employees first by gender and then by region
        Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
        System.out.println("Employees are grouped according to whether their salary is greater than 8000:" + part);
        System.out.println("Group of employees by gender:" + group);
        System.out.println("Employees by gender, region:"+ group2); }}Copy the code

Output results:

Employees based on whether the salary is greater than8000Grouping: {false=[Person{name='Jack', salary=7000, age=25, sex='male', area='Washington'}, Person{name='Lily', salary=7800, age=21, sex='female', area='New York'}].true=[Person{name='Tom', salary=8900, age=23, sex='male', area='Washington'}, Person{name='Anni', salary=8200, age=24, sex='female', area='New York'}]} Employees by gender: {female=[Person{name='Lily', salary=7800, age=21, sex='female', area='New York'}, Person{name='Anni', salary=8200, age=24, sex='female', area='New York'}], male=[Person{name='Tom', salary=8900, age=23, sex='male', area='Washington'}, Person{name='Jack', salary=7000, age=25, sex='male', area='Washington'{female={New York=[Person{name='Lily', salary=7800, age=21, sex='female', area='New York'}, Person{name='Anni', salary=8200, age=24, sex='female', area='New York'}]}, male={Washington=[Person{name='Tom', salary=8900, age=23, sex='male', area='Washington'}, Person{name='Jack', salary=7000, age=25, sex='male', area='Washington'}]}}

Process finished with exit code 0

Copy the code

Joint (joining)

Joining concatenates elements in stream into a string with a specific concatenation (or direct concatenation if not available).

public class StreamTest {

    public static void main(String[] args) {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom".8900.23."male"."New York"));
        personList.add(new Person("Jack".7000.25."male"."Washington"));
        personList.add(new Person("Lily".7800.21."female"."Washington"));
        String names = personList.stream().map(Person::getName).collect(Collectors.joining(","));
        System.out.println("Name of all employees:" + names);
        List<String> list = Arrays.asList("A"."B"."C");
        String string = list.stream().collect(Collectors.joining("-"));
        System.out.println("Concatenated string:" + string); }}Copy the code

Output results:

All employee names: Tom,Jack,Lily String: A-B-C Process finished withexit code 0

Copy the code

Sorting (sorted)

Sorted, intermediate operation. There are two kinds of sorting:

  • sorted(): Natural ordering, which elements in the stream need to implementComparableinterface
  • sorted(Comparator com):ComparatorCollator custom sort

Case study: Rank employees by salary from highest to lowest (and by age from highest to lowest for the same salary)

public class StreamTest {

    public static void main(String[] args) {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Sherry".9000.24."female"."New York"));
        personList.add(new Person("Tom".8900.22."male"."Washington"));
        personList.add(new Person("Jack".9000.25."male"."Washington"));
        personList.add(new Person("Lily".8800.26."male"."New York"));
        personList.add(new Person("Alisa".9000.26."female"."New York"));
        // Order in ascending order (natural order)
        List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName)
                .collect(Collectors.toList());
        // In reverse order of salary
        List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())
                .map(Person::getName).collect(Collectors.toList());
        // Order by salary first and then by age
        List<String> newList3 = personList.stream()
                .sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName)
                .collect(Collectors.toList());
        // Order by salary and then by age
        List<String> newList4 = personList.stream().sorted((p1, p2) -> {
            if (p1.getSalary() == p2.getSalary()) {
                return p2.getAge() - p1.getAge();
            } else {
                returnp2.getSalary() - p1.getSalary(); }}).map(Person::getName).collect(Collectors.toList());
        System.out.println("In ascending order of pay:" + newList);
        System.out.println("In descending order of pay:" + newList2);
        System.out.println("Rank by salary first and then ascending by age:" + newList3);
        System.out.println("Rank by salary first and then custom descending by age:"+ newList4); }}Copy the code

Output results:

Order by salary: [Lily, Tom, Sherry, Jack, Alisa] Order by salary: [Lily, Tom, Sherry, Jack, Alisa] Process finished withexit code 0

Copy the code

Extraction/combination

Streams can also be merged, deduplicated, restricted, or skipped.

public class StreamTest {

    public static void main(String[] args) {
        String[] arr1 = { "a"."b"."c"."d" };
        String[] arr2 = { "d"."e"."f"."g" };
        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);
        // concat: merges two streams distinct: deduplicates
        List<String> newList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
        // limit: limits the first n data to be obtained from the stream
        List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
        // skip: skip the first n data
        List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());
        System.out.println("Stream merge:" + newList);
        System.out.println("limit:" + collect);
        System.out.println("skip:"+ collect2); }}Copy the code

Output results:

[a, b, c, d, e, f, g] limit: [1.3.5.7.9.11.13.15.17.19Skip: [3.5.7.9.11]

Process finished with exit code 0

Copy the code

paging

The power of the STREAM API goes beyond the various combinations of collections to support paging.

For example, sort the following array from small to large. After sorting, query 10 items of data from the first row. The operation is as follows:

// The data to be queried
List<Integer> numbers = Arrays.asList(3.2.2.3.7.3.5.10.6.20.30.40.50.60.100);
List<Integer> dataList = numbers.stream().sorted(Integer::compareTo).skip(0).limit(10).collect(Collectors.toList());
System.out.println(dataList.toString());

Copy the code

Output results:

[2.2.3.3.3.5.6.7.10.20]

Process finished with exit code 0

Copy the code

Parallel operation

The so-called parallel, refers to multiple tasks at the same point in time, and by different CPUS for processing, do not preempt each other resources; Concurrency, on the other hand, refers to multiple tasks occurring simultaneously at the same time, but being processed by the same CPU, which preempts resources from each other.

For example, we use parallelStream to output the number of empty strings:

List<String> strings = Arrays.asList("abc".""."bc"."efg"."abcd".""."jkl");
// Get the number of empty strings using parallel computation
long count = strings.parallelStream().filter(String::isEmpty).count();
System.out.println(count);

Copy the code

In actual use,Parallel operationNot necessarily better thanSerial operationCome on! For simple operations, the number is very large, and the server is multi-core, it is recommended to use Stream parallel! On the contrary, serial operation is more reliable!

Set to Map operation

In the actual development process, one of the most frequently used operations is to use a primary key field in the set element as the key and the element as the value to realize the requirement of converting the set to a map. This requirement is widely used in data assembly.

public static void main(String[] args) {
    List<Person> personList = new ArrayList<>();
    personList.add(new Person("Tom".7000.25."male"."Anhui province"));
    personList.add(new Person("Jack".8000.30."female"."Beijing"));
    personList.add(new Person("Lucy".9000.40."male"."Shanghai"));
    personList.add(new Person("Airs".10000.40."female"."Shenzhen"));
    Map<Integer, Person> collect = personList.stream().collect(Collectors.toMap(Person::getAge, v -> v, (k1, k2) -> k1));
    System.out.println(collect);
}

Copy the code

Output results:

{40=Person{name='Lucy', salary=9000, age=40, sex='male', area='Shanghai'}, 25=Person{name='Tom', salary=7000, age=25, sex='male', area='anhui'}, 30=Person{name='Jack', salary=8000, age=30, sex='female', area='Beijing'}}

Process finished with exit code 0

Copy the code

Open the oughter.tomap method source code and take a look.

public static<T, K, U> Collector<T, ? , Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction) {return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}

Copy the code

As can be seen from the parameter table:

  • The first parameter: key
  • The second parameter: represents value
  • The third parameter: represents some kind of rule

The Collectors. ToMap (Person::getAge, v -> v, (k1,k2) -> k1), which means that the content of age is the key, v -> v means that the element Person is the value. Where (k1,k2) -> k1 means that if there is the same key, the first matching element will be the content, and the second one will be discarded!

Tags: [Java]