Java Basics - Streaming Computing Stream API


1. Basic concepts

In order to make it easier for engineers to process collection data, a new feature in Java8 is Stream (that is, stream, also known as stream computing). Using the newly provided Stream API, Java can iteratively process collections in a declarative manner, which is also similar to real pipeline production: stream = process + node + data.

Note on streams:

  • Lazy evaluation: If there is no final operation, the intermediate operation will not be executed
  • Streams are disposable: once a stream object has undergone a finalization operation, the stream cannot be used again
  • Does not affect the original data: We can do a lot of processing on the data in the stream, but under normal circumstances it will not affect the elements in the original collection

In order to more intuitively compare the traditional collection or array operation method and the streaming computing method, the following preparations have been made:

Define the Author class:

package StreamAPI;

import java.util.List;
@EqualsAndHashCode
public class Author {
    private long id;

    private String name;

    private Integer age;

    private String intro;

    private List<Book> books;

    public Author(long id, String name, Integer age, String intro, List<Book> books) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.intro = intro;
        this.books = books;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public String getIntro() {
        return intro;
    }

    public void setIntro(String intro) {
        this.intro = intro;
    }

    public List<Book> getBooks() {
        return books;
    }

    public void setBooks(List<Book> books) {
        this.books = books;
    }
}

   @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Author author = (Author) o;
        return id == author.id && Objects.equals(name, author.name) && Objects.equals(age, author.age) && Objects.equals(intro, author.intro) && Objects.equals(books, author.books);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, age, intro, books);
    }

Define the Book class:

package StreamAPI;
@EqualsAndHashCode
public class Book {
    private long id;

    private String name;

    private String category;

    private Integer score;

    private String intro;

    public Book(long id, String name, String category, Integer score, String intro) {
        this.id = id;
        this.name = name;
        this.category = category;
        this.score = score;
        this.intro = intro;
    }
   @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Book book = (Book) o;
        return id == book.id && Objects.equals(name, book.name) && Objects.equals(category, book.category) && Objects.equals(score, book.score) && Objects.equals(intro, book.intro);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, category, score, intro);
    }
}

Test class:

package StreamAPI;

import com.company.Task4_3;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class StreamDemo {
    public static void main(String[] args) {

    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中悟哲理的祖安人",null);
        Author author2 = new Author(2L,"亚拉索",15,"狂风也追逐不上他的思考速度",null);
        Author author3 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);
        Author author4 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);

        //书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L,"刀的两侧是光明与黑暗","哲学,爱情",88,"用一把刀分割了爱恨"));
        books1.add(new Book(2L,"一个人不能死在同一把刀下","个人成长,爱情",99,"讲述失恶"));

        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"哲学思想"));
        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"哲学思想"));
        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"哲学思想"));
        books2.add(new Book(4L,"吹或不吹","爱情,个人传记",56,"哲学"));

        books3.add(new Book(5L,"你的剑就是我的剑","爱情",56,"剑"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author,author2,author3,author4));
        return authorList;
    }
}

Now to get and print the names of writers whose age is younger than 18, we can use StreamAPI to print them in the following way:

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()//把集合转换成流
                .distinct()//去除重复元素
                .filter(author->author.getAge()<18) //过滤符合条件的作者
                .forEach(author->System.out.println(author.getName()));
    }

2. Create a stream

Single-column collection: collection object.stream()

	List<Author> authors = getAuthors();
	Stream<Author> stream = authors.stream();

Array: Arrays.stream (array) or Stream.of to create

	Integer[] arr = {1,2,3,4,5};
	Stream<Integer> stream = Arrays.stream(arr);
	Stream<Integer> stream2 = Stream.of(arr);

Two-column collection: Convert to a single-column collection and create

	Map<String,Integer> map = new HashMap<>();
	map.put("蜡笔小新",19);
	map.put("黑子",17);
	map.put("日向翔阳",16);
	Stream<Map.Entry<String,Integer>> stream = map.entrySet().stream();

3. Intermediate operation

3.1 filter

Elements in the stream can be filtered conditionally, and only those that meet the filter conditions can remain in the stream.

For example: output the names of writers whose name length exceeds 1

        List<Author> authors = getAuthors();
        authors.stream()//把集合转换成流
                .filter(author->author.getName().length()>1)
                .forEach(author->System.out.println(author.getName()));

3.2 map

Computations or transformations can be performed on the elements in the stream

For example: print the names of all writers, or convert the collection to a string type for later operations

 List<Author> authors = getAuthors();
        authors.stream()
                .map(new Function<Author, String>() {
                    @Override
                    public String apply(Author author) {
                        return author.getName();
                    }
                })
                .forEach(s->System.out.println(s));

3.3 distinct

Duplicate elements in the stream can be removed, relying on the equals method of Object to determine whether they are the same object. All you need to pay attention to is the need to override the equals method

Such as printing the names of all authors, which cannot have repeated elements

        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .forEach(author->System.out.println(author.getName()));

3.4 sorted

The elements in the stream can be sorted, and the Comparable interface must be implemented

For example, the elements in the convection stream are arranged in descending order according to age, and no duplicate elements are required.
The first way: call the sorted() method without parameters, because the Comparable interface needs to be implemented, so first modify the code of the Author class:

package StreamAPI;

import lombok.EqualsAndHashCode;

import java.util.List;
import java.util.Objects;

@EqualsAndHashCode
public class Author implements Comparable<Author> {
    private long id;

    private String name;

    private Integer age;

    private String intro;

    private List<Book> books;

    @Override
    public int compareTo(Author o) {
        return o.getAge() - this.getAge();
    }
}

Then sort the elements in descending order of age:

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .forEach(author->System.out.println(author.getName()));
    }

The second method: directly call the sorted() method with parameters, without implementing the Comparable interface:

        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted((o1,o2)->o2.getAge() - o1.getAge())
                .forEach(author->System.out.println(author.getName()));

3.5 limit

The maximum length of the stream can be set, and the excess will be discarded

If the elements in the convection flow are arranged in descending order of age, and there are no duplicate elements, then print the two elements with the oldest age

 List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted((o1,o2)->o2.getAge() - o1.getAge())
                .limit(2)
                .forEach(author->System.out.println(author.getName()));

3.6 skip

Skip n elements in the stream and return the remaining elements

If other writers other than the oldest writer are printed, it is required that there should be no repeated elements, and they should be arranged in descending order of age

        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted((o1,o2)->o2.getAge() - o1.getAge())
                .skip(1)//跳过第一个
                .forEach(author->System.out.println(author.getName()));

3.7 flatMap

map can only convert one object into another object as an element in the stream. And flatMap can convert an object into multiple objects as elements in the stream

For example: print the names of all books and require duplicate elements to be deduplicated

 List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(new Function<Author, Stream<Book>>() {
                    @Override
                    public Stream<Book> apply(Author author) {
                        return author.getBooks().stream();
                    }
                })
                .distinct()
                .forEach(book->System.out.println(book.getName()));

For example: to print all the categories of existing data, it is required to deduplicate the categories, and this format cannot appear: philosophy, love

        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(author->author.getBooks().stream())
                .distinct()
                .flatMap(book->Arrays.stream(book.getCategory().split(",")))
                .distinct()
                .forEach(category->System.out.println(category));

insert image description here

4. End operation

4.1 forEach

To traverse the elements in the stream, we use the parameters passed in to specify what specific operations to perform on the traversed elements

4.2 count

Can be used to get the number of elements in the current stream

Such as: print the number of all books of these authors, pay attention to delete duplicate elements

        List<Author> authors = getAuthors();
        long count = authors.stream()
                    .flatMap(author->author.getBooks().stream())
                    .distinct()
                    .count();
        System.out.println(count);

4.3 max&min

Can get the most value in the stream

Such as: Get the highest and lowest scores of these writers' books
Stream<Author> --> Stream<Book> --> Stream<Integer>(The type of score is int)

 List<Author> authors = getAuthors();
        Optional<Integer> max = authors.stream()
                .flatMap(author->author.getBooks().stream())
                .map(book->book.getScore())
                .max((score1,score2)->score1-score2);

        Optional<Integer> min = authors.stream()
                .flatMap(author->author.getBooks().stream())
                .map(book->book.getScore())
                .min((score1,score2)->score1-score2);

        System.out.println(min.get());
        System.out.println(max.get());

4.4 collect

Convert the current stream into a collection

For example: Get a List collection that stores all authors' names

        List<Author> authors = getAuthors();
       List<String> nameList = authors.stream()
               .map(author->author.getName())
               .collect(Collectors.toList());
       System.out.println(nameList);

Such as: Get a Set collection of all book titles

       Set<Book> books = authors.stream()
               .flatMap(author->author.getBooks().stream())
               .collect(Collectors.toSet());
       System.out.println(books);

For example: Get a Map collection, the key of the map is the author name, and the value is List<Book>

       Map<String,List<Book>> map = authors.stream()
       			.distinct()
               .collect(Collectors.toMap(author->author.getName(),author->author.getBooks()));

4.4 Find and match

anyMatch: used to determine whether there are any elements that meet the matching conditions, and the result is boolean type

For example: to determine whether there are writers over the age of 29

List<Author> authors = getAuthors();
       boolean flag = authors.stream()
               .anyMatch(author->author.getAge()>29);
       System.out.println(flag);

allMatch: Used to determine whether all match conditions are met

noneMatch: Determine whether none of the matching conditions are met

findAny: Get any element in the stream, this method has no way to guarantee which element in the stream must be obtained

findFirst: get the first element in the stream

4.5 reduce

Combining the elements in the stream, we can pass in an initial value, which will take the elements in the stream at one time and perform calculations based on the initial value according to our calculation method, and then calculate the calculation result with the subsequent elements.

It is calculated internally as follows:

	T result = identity;
	for(T element : this stream)
		result = accumulator.apply(result,element)
	return result;

Among them, identity is the initial value that we can pass in through the method parameters, and the specific calculation of the apply of the accumulator is also determined by us through the method parameters

Such as: Find the sum of the ages of all authors

        List<Author> authors = getAuthors();
        Integer sum = authors.stream()
                .distinct()
                .map(author->author.getAge())
                .reduce(0,(result,element)->result+element);//初始值为0,result为最终变量,element为遍历的元素值
        System.out.println(sum);

practise

Existing Employee entity class:

package StreamAPI;

public class Employee {
    public enum Type {MANAGER,SELLER,OFFICER};

    private String name;
    private String genger;
    private Integer age;
    private boolean married;
    private Type type;

    public Employee(String name, String genger, Integer age, boolean married, Type type) {
        this.name = name;
        this.genger = genger;
        this.age = age;
        this.married = married;
        this.type = type;
    }

    public String getName() {
        return name;
    }

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

    public String getGenger() {
        return genger;
    }

    public void setGenger(String genger) {
        this.genger = genger;
    }

    public Integer getAge() {
        return age;
    }

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

    public boolean isMarried() {
        return married;
    }

    public void setMarried(boolean married) {
        this.married = married;
    }

    public Type getType() {
        return type;
    }

    public void setType(Type type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", genger='" + genger + '\'' +
                ", age=" + age +
                ", married=" + married +
                ", type=" + type +
                '}';
    }
}

Company entity class:

package StreamAPI;

import java.util.List;

public class Company<T> {
    public enum Type{BIG,SMALL};

    private String name;
    private Type type;
    private List<T> employee;

    public Company(String name, Type type, List<T> employee) {
        this.name = name;
        this.type = type;
        this.employee = employee;
    }

    public String getName() {
        return name;
    }

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

    public Type getType() {
        return type;
    }

    public void setType(Type type) {
        this.type = type;
    }

    public List<T> getEmployee() {
        return employee;
    }

    public void setEmployee(List<T> employee) {
        this.employee = employee;
    }

    @Override
    public String toString() {
        return "Company{" +
                "name='" + name + '\'' +
                ", type=" + type +
                ", employee=" + employee +
                '}';
    }
}

Then insert the following data into the collection:

 List<Company<Employee>> list = new ArrayList<>();
        List<Employee> employees = Arrays.asList(
                new Employee("张勇","男",28,true,Employee.Type.MANAGER),
                new Employee("李强","男",22,false,Employee.Type.SELLER),
                new Employee("王五","男",32,false,Employee.Type.SELLER),
                new Employee("梅丽","女",26,true,Employee.Type.OFFICER),
                new Employee("郑帅","男",29,false,Employee.Type.OFFICER),
                new Employee("曾美","女",27,true,Employee.Type.SELLER),
                new Employee("郝俊","男",22,true,Employee.Type.SELLER),
                new Employee("方圆","女",24,false,Employee.Type.SELLER)
                );
        Company<Employee> moubao = new Company<Employee>("某宝",Company.Type.BIG,employees);

        employees = Arrays.asList(
                new Employee("吴琼","女",27,true,Employee.Type.SELLER),
                new Employee("陈辰","女",28,false,Employee.Type.OFFICER),
                new Employee("刘能","男",35,true,Employee.Type.OFFICER),
                new Employee("周七","男",29,false,Employee.Type.OFFICER),
                new Employee("汪旺","男",21,false,Employee.Type.OFFICER),
                new Employee("胡涂","男",27,false,Employee.Type.OFFICER),
                new Employee("杨茂","男",34,true,Employee.Type.MANAGER),
                new Employee("朱坚","男",30,false,Employee.Type.MANAGER)
        );
        Company<Employee> mouxin = new Company<Employee>("某东",Company.Type.BIG,employees);

        employees = Arrays.asList(
                new Employee("冯过","男",35,false,Employee.Type.SELLER),
                new Employee("何花","女",27,false,Employee.Type.MANAGER),
                new Employee("卫精","男",25,true,Employee.Type.OFFICER),
                new Employee("施工","男",28,false,Employee.Type.OFFICER),
                new Employee("沈月","女",24,false,Employee.Type.OFFICER),
                new Employee("乐欢","女",22,false,Employee.Type.OFFICER),
                new Employee("安全","男",33,true,Employee.Type.MANAGER),
                new Employee("林森","男",26,true,Employee.Type.SELLER)
        );
        Company<Employee> wahaha = new Company<Employee>("某哈哈",Company.Type.SMALL,employees);

        //加入列表
        list.add(moubao);
        list.add(mouxin);
        list.add(wahaha);

Realize the following requirements: count all unmarried employees whose company type is BIG, sort by age at the same time, and unmarried employees do not distinguish between companies, that is, the final results are placed in a list (hint: the entire requirement can be completed with one line of code)

        List<Employee> employeeList = list.stream()
                .filter(conpany->conpany.getType() == Company.Type.BIG)
                .flatMap(company->company.getEmployee().stream())
                .filter(employee -> employee.isMarried() == false)
                .sorted((o1,o2)->o1.getAge() - o2.getAge() )
                .collect(Collectors.toList());
        for(Employee e : employeeList)
            System.out.println(e.toString());

insert image description here

Guess you like

Origin blog.csdn.net/weixin_46025531/article/details/122778572