The Java 8 API adds a new abstraction called a Stream, which lets you process data declaratively, with the collection of elements to be processed as a Stream

A stream travels in a pipe and can be processed at the nodes of the pipe, such as filtering, sorting, aggregating, etc., through intermediate operations in the pipe, and finally the result of the previous processing is obtained by the final operation.

In summary, the use of stream generally involves three things:

A data source, such as a collection, to execute a query;

An intermediate operation chain, forming a flow line;

A terminal operation performs pipelining and generates results.

Intermediate operations, for example

Filter (), map(), sorted(), skip(), peek

Terminal operations, for example

AllMatch (), anyMatch(), noneMatch(), forEach(), collect(), count()

With pipelining (pipelining operations can be viewed as database-like queries against data sources) and internal iteration, the Stream API allows for cleaner, more readable, more flexible, and better performance code

In Java 8, the collection interface has two methods to generate streams:

  • Stream () − Creates a serial stream for the collection.
  • ParallelStream () − Creates parallel streams for collections

Familiarize yourself with the use of Stream with a simple example

Create a User class and perform various stream operations

@Data @AllArgsConstructor public class User { public Long id; private String name; private Integer age; private Double grades; private String sex; /** ** private String usualGrades; }Copy the code

Flow operation

// Query the name of the user whose score passed
List<String> nameList1 = users.stream().filter(x -> x.getGrades() > 60).map(User::getName).collect(Collectors.toList());


Select * from top 3 where id = 1
List<String> nameList2 = users.stream().sorted(Comparator.comparingDouble(User::getGrades).reversed().thenComparingLong(User::getId))
        .limit(3).map(User::getName).collect(Collectors.toList());


// Count the number of boys
long num = users.stream().filter(x -> x.getSex().equals("Male")).count();

// Count the total score of the class
Integer collect = users.stream().map(x -> x.getUsualGrades().split(",")).flatMap(Arrays::stream).collect(Collectors.summingInt(x -> Integer.parseInt(x)));


// Check if there is a student named Xiao Ming in the class
boolean flag = users.stream().anyMatch(x -> x.getName().equals("Xiao Ming"));


// Check if everyone in the class begins with "small"
boolean flag2 = users.stream().allMatch(x -> x.getName().startsWith("Small"));

// Prints all information
 users.stream().forEach(System.out::println);


Copy the code

Through the above operations, we also have a brief understanding of some flow operations

  • A filter accepts a Lambda and either excludes or extracts elements from the stream
  • The map takes a Lambda, converts the element to another form or extracts the element
  • Collect converts the stream to another form
  • Sorted sorts some elements
  • Limit truncates a stream so that it does not exceed a given number of elements
  • FlatMap splits the content of each mapping stream into multiple identical streams. (For example, in the above example, each student has a quarter of the content. Now extract them into fractions.)
  • AnyMatch matches any of them and returns Boolean
  • AllMatch matches all elements and returns Boolean
  • FindAny looks for any of them and returns Optional
  • FindFirst returns Optional if it finds the first one
  • ForEach iterates through all the information

There are other powerful stream operations worth finding. In the above operations, most of them are statements that accept a Laombda expression. If you click on the source code, you can see that it’s passed a functional interface, such as filter, Predicate interface, and there’s only one method, test, Pass in a parameter that returns a Boolean type

Functional interface

An interface that has one and only abstract methods but can have multiple non-abstract methods. FunctionalInterface is annotated to indicate that an interface is a FunctionalInterface that can be implicitly converted to a lambda expression.

Common functional interfaces:

  • The default method is void accept(T T). ForEach () is used as a stream operation
  • Function R apply(T T) is a Function that takes an input parameter and returns a result
  • Predicate asserts. The default method is Boolean test(T T), used by the filter() stream operator
  • Supplier provides, supplies, defaults to T get()
  • BiConsumer

    represents an operation that takes two input parameters and returns no results
    ,u>
  • BiFunction

    represents a method that takes two input parameters and returns a result
    ,u,r>
  • IntConsumer takes an input parameter of type int, with no return value
  • IntToDoubleFunction takes an int input and returns a double result
  • ToIntFunction takes an input parameter and returns a result of type int.