Lamdba03 Java 8 new feature 4: Stream API

Posted by able on Sat, 19 Feb 2022 16:15:58 +0100


Two major changes in Java 8 are Lambda expressions and Stream API expressions. Stream is a key abstract concept for processing sets in Java 8. It can perform very complex operations such as searching, filtering and filtering on sets. Stream has also been added to the new version of JPA [connect database].
Stream API brings us powerful functions to operate the collection. At the same time, stream API is simple and easy to use.

for example

@Query("select u from User u")
Stream<User> findAllByCustomQueryAndStream();

Stream<User> readAllByFirstnameNotNull();

@Query("select u from User u")
Stream<User> streamAllPaged(Pageable pageable);

Operation steps of Stream

Stream has the following three operation steps:

1, Create Stream
Get a stream from a data source, such as a collection or array.
2, Intermediate operation
An intermediate chain of operations, which operates on the data of the data source.
3, Terminate operation
A termination operation that executes an intermediate chain of operations and produces results.
Note: after the convection operation is completed, it needs to be turned off

Take a simple example:

Suppose there is a Person class and a Person list. Now there are two requirements: 1) find people older than 18 and output them; 2) Find out the number of all Chinese.

@Data
class Person {
    private String name;
    private Integer age;
    private String country;
    private char sex;

    public Person(String name, Integer age, String country, char sex) {
        this.name = name;
        this.age = age;
        this.country = country;
        this.sex = sex;
    }
}
List<Person> personList = new ArrayList<>();
personList.add(new Person("Ouyang Xue",18,"China",'F'));
personList.add(new Person("Tom",24,"U.S.A",'M'));
personList.add(new Person("Harley",22,"britain",'F'));
personList.add(new Person("Smile to the sky",20,"China",'M'));
personList.add(new Person("Kang Li",22,"China",'M'));
personList.add(new Person("Xiaomei",20,"China",'F'));
personList.add(new Person("He Xue",21,"China",'F'));
personList.add(new Person("Kang Li",22,"China",'M'));

Before JDK8, we can complete it by traversing the list. However, with the Stream API, it can be implemented as follows:

 public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("Ouyang Xue", 18, "China", 'F'));
        personList.add(new Person("Tom", 24, "U.S.A", 'M'));
        personList.add(new Person("Harley", 22, "britain", 'F'));
        personList.add(new Person("Smile to the sky", 20, "China", 'M'));
        personList.add(new Person("Kang Li", 22, "China", 'M'));
        personList.add(new Person("Xiaomei", 20, "China", 'F'));
        personList.add(new Person("He Xue", 21, "China", 'F'));
        personList.add(new Person("Kang Li", 22, "China", 'M'));


//    1) Find people older than 18 and output them;
//Create stream object Boolean test (T); void accept(T t);
        personList.stream().filter(t->t.getAge()>20).forEach(t->System.out.println(t));
//        Method reference in lamdba
personList.stream().filter(t->t.getAge()>20).forEach(System.out::println);

//    2) Find out the number of all Chinese. count() calculate quantity
    long c = personList.stream().filter(t -> t.getCountry().equals("China")).count();

        System.out.println(c);
    }

In this example, personlist Stream () is to create a stream, filter() is an intermediate operation, and forEach and count() are termination operations.

Stream intermediate operation – filter and slice parallel streams with parallelStream

filter: receive Landba and exclude some operations from the stream
limit: truncate the stream so that its elements do not exceed the given object
Skip (n): skip elements and return a stream that discards the first n elements. If there are less than n elements in the stream, an empty stream will be returned, which is complementary to limit (n)
distinct: filter to remove duplicate elements through hashCode () and equals () of the elements generated by the stream.

limit example

Demand, take two women from the Person list.

//        Take two women from the Person list. limit
      personList.stream().filter(t -> t.getSex() == 'F').limit(2).forEach(System.out::println);

skip example

Start with the second woman in the Person list and take out all women.

//        Start with the second woman in the Person list and take out all women. skip(1) means skip the first one
        personList.stream().filter(t->t.getSex()=='F').skip(1).forEach(System.out::println);

distinct example

//        duplicate removal
        personList.stream().distinct().forEach(System.out::println);

Stream intermediate operation - mapping

  • map – receive Lambda, convert elements into other forms or extract information. Receive a function as an argument, which will be applied to each element and mapped to a new element.
  • flatMap – take a function as a parameter, change each value in the stream into another stream, and then connect all streams into one stream

map example

For example, we use a PersonCountry class to receive all country information

//        For example, we use a PersonCountry class to receive all country information r apply (T);
        personList.stream().map(t->t.getCountry()).forEach(System.out::println);

Receiving all names and countries first encapsulates an entity class with two fields

//      Receiving all names and countries first encapsulates an entity class with two fields
        personList.stream().map(t->new NameAndCountry(t.getName(),t.getCountry())).forEach(System.out::println);
@Data
@AllArgsConstructor
@NoArgsConstructor
class  NameAndCountry{
    private String name;
    private String country;
}

Sort the previous personList according to the age from small to large. If the age is the same, then sort by name

//Sort the previous personList according to the age from small to large. If the age is the same, then sort by name
//This class must be used to implement natural sorting
//        personList.stream().sorted();
//           int compare(T o1, T o2);
//        The first method
        personList.stream().sorted((o1, o2) -> {
            if (o1.getAge() == o2.getAge()) {
                return o1.getName().compareTo(o2.getName());
            }
            return o1.getAge() - o2.getAge();
        }).forEach(System.out::println);
        System.out.println("-----------------");
//The second method uses the ternary operator
        personList.stream().sorted((o1, o2) ->o1.getAge()==o2.getAge()?o1.getName().compareTo(o2.getName()):o1.getAge()-o2.getAge()).forEach(System.out::println);

summary

1. filter(Predicate)
2. limit(long)
3. skip(long)
4. distinct();
5. map(Function)
6. sorted()  | sorted(Comparator)

Terminate operation – find and match

  • allMatch – check to see if all elements match
  • anyMatch – check to see if at least one element matches
  • noneMatch – check if all elements are not matched
  • findFirst – returns the first element
  • findAny – returns any element in the current stream
  • count – returns the total number of elements in the stream
  • max – returns the maximum value in the stream
  • min – returns the minimum value in the stream

These aspects are described in the Stream class. Here are not examples one by one, but only one example of allMatch and max.

allMatch checks whether at least one element is matched

Determine whether all the people in the personList are over 18 years old

//Check to see if at least one element matches
        boolean b = personList.stream().anyMatch(item -> item.getAge() >18);
        System.out.println(b);

Determine whether all the people in the personList are adults

//        Judge whether all the people in the personList are Chinese:
        boolean b1 = personList.stream().allMatch(p -> p.getCountry().equals("China"));
        System.out.println(b1);

findAny returns any element in the current stream

//Returns any element in the current stream
        Optional<Person> any = personList.stream().findAny();
        System.out.println(any);
//Returns any element in the current stream
//        Person person = personList.stream().findAny().get();
        Person person = personList.parallelStream().findAny().get();
        System.out.println(person);

max - returns the maximum value in the stream

Find the oldest in the personList

//        Find the oldest int compare(T o1, T o2);
        Optional<Person> max = personList.stream().max((o1, o2) -> o1.getAge() - o2.getAge());
        System.out.println(max);

reduction

The reduction operation of Stream API can repeatedly combine the elements in the stream to obtain a value, including

Optional<T> reduce(BinaryOperator<T> accumulator);

T reduce(T identity, BinaryOperator<T> accumulator);

<U> U reduce(U identity,
                 BiFunction<U, ? super T, U> accumulator,
                 BinaryOperator<U> combiner);

Find a sum of 1 to 100

First method:
The second method of reduce is used: t reduce (t identity, binary operator accumulator)

        //        Find the sum protocol of 1-100
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(new Random().nextInt(10));
        }
        System.out.println(list);
//    R apply(T t, T u,T r);
        Optional<Integer> reduce = list.stream().reduce((t, u) -> t + u);
        System.out.println(reduce);

Disassemble this action, and its operation steps are simulated as follows:
0 (1,2) -> 1 + 2 + 0
3 (3,4) -> 3 + 4 + 3
10 (5,6) -> 5 + 6 + 10
The operation step is to add the two elements of the list each time, and accumulate the result with the addition result of the previous two elements. Therefore, at the beginning, set the identity to 0, because the first element and the second element have not been operated before when they are added
The second method:

     Integer[] list = {1, 2, 3, 4, 5};
        System.out.println(Arrays.asList(list));

        Arrays.stream(list).reduce((t,u)->{
            System.out.println(t+"-----"+u);
            return t+u;
        });
        System.out.println(Arrays.asList(list));

Ask for the sum of all people's ages

//        Ask for the sum of all people's ages
        Optional<Integer> reduce = personList.stream().map(item -> item.getAge()).reduce((t, u) -> t + u);
        System.out.println(reduce);

Find the average age of everyone

Collectors.averagingDouble

//averagingDouble
        Double collect1 = personList.stream().collect(Collectors.averagingDouble(t -> t.getAge()));
        System.out.println(collect1);

Find the set of all people's ages

collect(Collectors.toList())

        List<Integer> collect = personList.stream().map(item -> item.getAge()).collect(Collectors.toList());

Find the maximum age of everyone in the set

//        Find the maximum age in the set
        Optional<Person> collect2 = personList.stream().collect(Collectors.maxBy((o1, o2) -> o1.getAge() - o2.getAge()));
        System.out.println(collect2);

Minimum age type.
There are other operations, you can refer to Java util. stream. Collectors.

Pay attention to the closure of the flow

Find the minimum age of everyone in the set.

 try(final Stream<Integer> integerStream = personList.stream().map(Person::getAge)) {
   final Optional<Integer> minAge = integerStream.collect(Collectors.minBy(Integer::compareTo));
   System.out.println(minAge.get());
}

It is better to put the stream operation in try with resources. For convenience, the previous content in this chapter is not put in try with resources.

Complete test code

package com.zz.lamdab.lamdba04;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class Deom1 {
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("Ouyang Xue", 18, "China", 'F'));
        personList.add(new Person("Tom", 24, "U.S.A", 'M'));
        personList.add(new Person("Harley", 22, "britain", 'F'));
        personList.add(new Person("Smile to the sky", 20, "China", 'M'));
        personList.add(new Person("Kang Li", 22, "China", 'M'));
        personList.add(new Person("Xiaomei", 20, "China", 'F'));
        personList.add(new Person("He Xue", 21, "China", 'F'));
        personList.add(new Person("Kang Li", 22, "China", 'M'));


//    1) Find people older than 18 and output them;
//Create stream object Boolean test (T); void accept(T t);
        personList.stream().filter(t -> t.getAge() > 20).forEach(t -> System.out.println(t));
//        Method reference in lamdba
        personList.stream().filter(t -> t.getAge() > 20).forEach(System.out::println);

//    2) Find out the number of all Chinese. count() calculate quantity
        long c = personList.stream().filter(t -> t.getCountry().equals("China")).count();

        System.out.println(c);

//        Take two women from the Person list. limit
        personList.stream().filter(t -> t.getSex() == 'F').limit(2).forEach(System.out::println);

//        Start with the second woman in the Person list and take out all women. skip(1) means skip the first one
        personList.stream().filter(t -> t.getSex() == 'F').skip(1).forEach(System.out::println);
        System.out.println("-----------------");
//        duplicate removal
        personList.stream().distinct().forEach(System.out::println);
        System.out.println("-----------------");

//        For example, we use a PersonCountry class to receive all country information r apply (T);
        personList.stream().map(t -> t.getCountry()).forEach(System.out::println);
//      Receiving all names and countries first encapsulates an entity class with two fields
        personList.stream().map(t -> new NameAndCountry(t.getName(), t.getCountry())).forEach(System.out::println);

        System.out.println("-----------------");
//Sort the previous personList according to the age from small to large. If the age is the same, then sort by name
//This class must be used to implement natural sorting
//        personList.stream().sorted();
//           int compare(T o1, T o2);
//        The first method
        personList.stream().sorted((o1, o2) -> {
            if (o1.getAge() == o2.getAge()) {
                return o1.getName().compareTo(o2.getName());
            }
            return o1.getAge() - o2.getAge();
        }).forEach(System.out::println);
        System.out.println("-----------------");
//The second method uses the ternary operator
        personList.stream().sorted((o1, o2) ->o1.getAge()==o2.getAge()?o1.getName().compareTo(o2.getName()):o1.getAge()-o2.getAge()).forEach(System.out::println);
        System.out.println("-----------------");
//Returns any element in the current stream
        Optional<Person> any = personList.stream().findAny();
        System.out.println(any);
        System.out.println("-----------------");
//        Check to see if at least one element matches
        boolean b = personList.stream().anyMatch(item -> item.getAge() >18);
        System.out.println(b);
//        Judge whether all the people in the personList are Chinese:
        boolean b1 = personList.stream().allMatch(p -> p.getCountry().equals("China"));
        System.out.println(b1);
//Returns any element in the current stream
//        Person person = personList.stream().findAny().get();
        Person person = personList.parallelStream().findAny().get();
        System.out.println(person);

//        Find the oldest int compare(T o1, T o2);
        Optional<Person> max = personList.stream().max((o1, o2) -> o1.getAge() - o2.getAge());
        System.out.println(max);



//        Ask for the sum of all people's ages
        Optional<Integer> reduce = personList.stream().map(item -> item.getAge()).reduce((t, u) -> t + u);
        System.out.println(reduce);

        List<Integer> collect = personList.stream().map(item -> item.getAge()).collect(Collectors.toList());
//averagingDouble
        Double collect1 = personList.stream().collect(Collectors.averagingDouble(t -> t.getAge()));
        System.out.println(collect);
        System.out.println(collect1);
//        Find the maximum age in the set
        Optional<Person> collect2 = personList.stream().collect(Collectors.maxBy((o1, o2) -> o1.getAge() - o2.getAge()));
        System.out.println(collect2);
//        Pay attention to the closure of the flow
//        Stream<Integer> integerStream = personList.stream().map(Person::getAge);


        try(final Stream<Integer> integerStream = personList.stream().map(Person::getAge)) {
            final Optional<Integer> minAge = integerStream.collect(Collectors.minBy(Integer::compareTo));
            System.out.println(minAge.get());

        }

    }


}

@Data
class Person {
    private String name;
    private Integer age;
    private String country;
    private char sex;

    public Person(String name, Integer age, String country, char sex) {
        this.name = name;
        this.age = age;
        this.country = country;
        this.sex = sex;
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class NameAndCountry {
    private String name;
    private String country;
}

Topics: Java stream