1. Why use lambda

1.1 Precursors

All of the following examples are shown as follows

package com.omg;

import java.util.Objects;

public class Employe {

    private String name;
    private int age;
    private double salary;

    public Employe(a) {}public Employe(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public Employe(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName(a) {
        return name;
    }

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

    public int getAge(a) {
        return age;
    }

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

    public double getSalary(a) {
        return salary;
    }

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

    @Override
    public String toString(a) {
        return "Employe{" +
                "name='" + name + '\' ' +
                ", age=" + age +
                ", salary=" + salary +
                '} ';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null|| getClass() ! = o.getClass())return false;
        Employe employe = (Employe) o;
        return age == employe.age &&
                Double.compare(employe.salary, salary) == 0 &&
                Objects.equals(name, employe.name);
    }

    @Override
    public int hashCode(a) {
        returnObjects.hash(name, age, salary); }}Copy the code

Using the above Employe Class to generate a list:

    List<Employe> employees = Arrays.asList(
        new Employe("Zhang".18.9999.99),
        new Employe("Bill".39.5555.55),
        new Employe("Fifty".50.666.99),
        new Employe("Daisy".16.6666.66),
        new Employe("Cropland 7".8.8888.88),
        new Employe("Cropland 7".40.8888.88),
        new Employe("Cropland 7".60.8888.88));Copy the code

1.2 contrast

Requirements: Filter out all employees whose salary is more than 5000 and those whose age is more than 35. This can be achieved in the following ways:

  • Traditional function implementation
  • Policy pattern + inheritance
  • Policy pattern + anonymous inner class
  • Policy pattern + lambda
  • Stream

By comparison, the Stream code implementation is the most concise and efficient

package com.omg;

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

/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** *
public class Main {

    List<Employe> employes = Arrays.asList(
            new Employe("Zhang".18.9999.99),
            new Employe("Bill".38.5555.99),
            new Employe("Fifty".50.6666.66),
            new Employe("Daisy".16.3333.33),
            new Employe("Cropland 7".10.7777.77));/* Method 1: filter */ by function
    public void filterByFunction(a){
        System.out.println("Employees earning more than 5,000:" + filterSalary(employes));
        System.out.println("Employees older than 35:" + filterAge(employes));
    }

    public static List<Employe> filterSalary(List<Employe> employes){
        if (null == employes || employes.isEmpty()){
            return null;
        }

        List<Employe> result =  new ArrayList<>();
        for (Employe employe:employes){
            if (employe.getSalary() > 5000){ result.add(employe); }}return result;
    }

    public static List<Employe> filterAge(List<Employe> employes){
        if (null == employes || employes.isEmpty()){
            return null;
        }

        List<Employe> result =  new ArrayList<>();
        for (Employe employe:employes){
            if (employe.getAge() > 35){ result.add(employe); }}return result;
    }

    / * * * * * * * * * * * * * * * * * * * * * * * * * strategy pattern, an anonymous inner class, lambda public module begin * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /

    interface MyPredicate<T> {
        public boolean test(T t);
    }

    public static List<Employe> filterEmploye(List<Employe> employes, MyPredicate<Employe> predicate){
        if (null == employes || employes.isEmpty()){
            return null;
        }

        List<Employe> result =  new ArrayList<>();
        for (Employe employe:employes){
            if(predicate.test(employe)){ result.add(employe); }}return result;
    }
    / * * * * * * * * * * * * * * * * * * * * * * * * * strategy pattern, an anonymous inner class, lambda public module end * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /

    /** * Mode 2: Use policy mode */
    class filterEmployeBySalary implements MyPredicate<Employe>{
        @Override
        public boolean test(Employe employe) {
            returnemploye! =null && employe.getSalary() > 5000; }}class filterEmployeByAge implements MyPredicate<Employe>{
        @Override
        public boolean test(Employe employe) {
            returnemploye ! =null && employe.getAge() > 35; }}public void filterByStrategyPattern(a){
        System.out.println("Employees earning more than 5,000:" + filterEmploye(employes, new filterEmployeBySalary()));
        System.out.println("Employees older than 35:" + filterEmploye(employes, new filterEmployeByAge()));
    }

    /** * Method 3: use anonymous inner classes to implement */
    public  void filterByAnonymousClasses(a){
        System.out.println("Employees earning more than 5,000:" + filterEmploye(employes, new MyPredicate<Employe>() {
            @Override
            public boolean test(Employe employe) {
                returnemploye! =null && employe.getSalary() > 5000; }})); System.out.println("Employees older than 35:" + filterEmploye(employes, new MyPredicate<Employe>() {
            @Override
            public boolean test(Employe employe) {
                returnemploye! =null && employe.getAge() > 35; }})); }/** * Method 4: using the lambda expression */
    public  void filterByLambda(a){
        System.out.println("Employees earning more than 5,000:"+ filterEmploye(employes, (employe)->employe! =null && employe.getSalary()>5000));
        System.out.println("Employees older than 35:"+ filterEmploye(employes, (employe)->employe! =null && employe.getAge() > 35));
    }

    /** * Method 5: implement * via stream@param args
     */
    public  void filterByStream(a){
        System.out.print("Employees earning more than 5,000:"); employes.stream() .filter((employe)->employe! =null && employe.getSalary()>5000)
                .forEach(System.out::print);
        System.out.println();
        System.out.print("Employees older than 35:"); employes.stream() .filter((employe)->employe! =null && employe.getAge()>35)
                .forEach(System.out::print);
        System.out.println();
    }

    public static void main(String[] args) {
        Main  main = new Main();
        System.out.println("-----------function------------");
	     main.filterByFunction();
        System.out.println("-----------Strategy Pattern------------");
         main.filterByStrategyPattern();
        System.out.println("------------Anonymous Classes-----------");
         main.filterByAnonymousClasses();
        System.out.println("-------------Lambda----------");
         main.filterByLambda();
        System.out.println("------------Stream-----------"); main.filterByStream(); }}Copy the code

2.Lambda

2.1 Basic Grammar

Basic syntax for Lambda expressions: Java8 introduced a new operator “->”. This operator is called the arrow operator or Lambda operator. The arrow operator splits a Lambda expression into two parts:

  • Left: List of arguments to the Lambda expression
  • Right side: The function required to perform in a Lambda expression, known as the Lambda body

The basic grammar rules are as follows:

  1. No parameter, no return value;
Runnable ri = ()-> System.out.println("Lambda syntax format 1: No arguments, no return value");
Copy the code
  1. There is one argument and no return value;
Consumer<String> consumer = (x)-> System.out.println(x);
Copy the code
  1. If there is only one parameter, the parentheses can be omitted (the second method is based on optimization).
 Consumer<String> consumer1 = x-> System.out.println(x);
Copy the code
  1. Have more than two parameters, have a return value, and Lambda weight has multiple statements;
Comparator<Integer> com = (x,y)-> {
    System.out.println("Functional interface");
    return Integer.compare(x, y);
};
Copy the code

5. If there is only one statement in the Lambda body, return and curly braces can be omitted

 Comparator<Integer> com = (x,y)-> Integer.compare(x, y);
Copy the code
  1. The data type of the argument list of a Lambda expression can be omitted because the JVM compiler deduces the data type from the context, which is called type inference.
Comparator<Integer> com1 = (Integer x,Integer y)-> Integer.compare(x, y);
// The parameter type can be omitted
Comparator<Integer> com2 = (x,y)-> Integer.compare(x, y);
Copy the code

The complete code example is as follows:

package com.omg.lambda;

import jdk.jfr.StackTrace;

import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;

The arrow operator divides the Lambda expression into two parts: ** The left side of the Lambda expression: List of arguments to the Lambda expression * right: functions to be performed in the Lambda expression, i.e. Lambda body * * Syntax format 1: No arguments, no return value * () -> System.out.println("Hello Lambda!") ); Println (x) -> system.out.println (x) -> system.out.println (x) * x -> system.out.println (x) * * * Comparator
      
        com = (x,y)-> {* system.out.println (" functional interface "); * return Integer.compare(x, y); *}; * Comparator
       
         com = (x,y)-> Integer.compare(x, y); * * Syntax format 6: The data type of the argument list of a Lambda expression can be omitted because the JVM compiler can infer from the context that the data type is "type inferred" * (Integer x,Integer y)-> Integer.compare(x, y); * * upper couplet: left and right meet a parenthesis province * lower couplet: left inference type province * horizontal batch: can save the province */
       
public class Test1Lambda {

    public static void main(String[] args) {
        /* Syntax format 1: no parameter, no return value */
        Runnable ri = ()-> System.out.println("Lambda syntax format 1: No arguments, no return value");
        ri.run();

        /* Syntax format 2: one parameter and no return value */
        Consumer<String> consumer = (x)-> System.out.println(x);
        consumer.accept("Lambda syntax format 2: One argument and no return value");

        /* Syntax format 3: If there is only one parameter, the parentheses can be omitted without */
        Consumer<String> consumer1 = x-> System.out.println(x);
        consumer1.accept("Lambda syntax format 3: If there is only one argument, the parentheses may be omitted.");

        /* Syntax format 4: have more than two arguments, have a return value, and the Lambda weight has multiple statements */
        BiFunction<String, String, String> function = (x,y)->{
            if (null == x || x.isEmpty()){
                x = "lambda ";
            }
            if (null == y || y.isEmpty()){
                y = "Syntax format four: has more than two arguments, has a return value, and Lambda weight has multiple statements.";
            }

            return x+y;
        };
        System.out.println(function.apply(null.null));

        If there is only one statement in the body of a Lambda, return and curly braces can be omitted without */
        Supplier<String> supplier = ()->"Lambda syntax format 5: If there is only one statement in the body of a lambda, return and curly braces can be omitted.";
        System.out.println(supplier.get());

        /* Syntax format 6: The data type of the argument list of a Lambda expression can be omitted because the JVM compiler deduces the data type from the context, i.e. "type inference" (Integer x,Integer y)-> Integer.compare(x, y)*/
        BiFunction<String, String, String> function1 = (String x, String y)->x+y;
        // The JVM compiler can infer the type of the parameterBiFunction<String, String, String> function2 = (x, y)->x+y; }}Copy the code

2.2 Method Reference

2.2.1 Method reference

The content in the body of a Lambda expression is already implemented by a method, so we can use a “method reference”

Lambda expresses that the argument list and return type of the calling method in the entity must be consistent with that of the abstract method in the functional interface. The basic syntax for method references is as follows:

  1. Object :: Instance method

The lambda expression is: a -> x.unction (a), which can be simplified to x::function, where x is a variable that has been applied for in advance

    System.out.println("Lambda expression: a -> x.unction (a) can be simplified to x::function, x is a pre-requested variable");
    PrintStream ps = System.out;
    Consumer<String> con1 = (s) -> ps.println(s);
    con1.accept((s) -> ps.println(s));
    Consumer<String> con2 = ps::println;
    con2.accept("Object :: instance method, optimization write: ps::println");
Copy the code

2. Class :: Static methods

Lambda expression is: (a,b) -> classname. staticMethod(a, b) can be simplified to ClassName::function

    System.out.println("Lambda expression: (a,b) -> ClassName. StaticMethod (a,b) can be reduced to ClassName::function");
    BinaryOperator<Integer> max = (x, y) -> Integer.max(x, y);
    BinaryOperator<Integer> max2 = Integer::max;
    System.out.println("Class :: static method, primitive: BinaryOperator
      
        Max = (x, y) -> integer.max (x, y);"
      );
    System.out.println("Class :: static method, optimizer: BinaryOperator
      
        max2 = Integer:: Max;"
      );
Copy the code

Class :: instance methods

Lambda as (x)->x.method() can be optimized to xClassName::method

Lambda is (x, y)->x.method(y) can be optimized to xClassName::method

    System.out.println("Class :: instance method optimization 1, lambda is (x)->x.method() can be optimized to xClassName::method");
    Function<String, String> upper = x -> x.toUpperCase();
    Function<String, String> upper2 = String::toUpperCase;
    System.out.println(Function
      
        upper = x -> x.topperCase ();
      ,>);
    System.out.println(Function
      
        upper2 = String::toUpperCase;
      ,>);

    System.out.println("");
    System.out.println("Class :: instance method optimization 2, lambda is (x, y)->x.method(y) can be optimized to xClassName::method");
    BiFunction<String, String, Boolean> compare = (x,y) -> x.equals(y);
    BiFunction<String, String, Boolean> compare2 = String::equals;
    System.out.println("Class :: instance method: BiFunction
      
        compare = (x,y) -> x.equals(y);"
      ,>);
    System.out.println("BiFunction
      
        compare2 = String::equals;"
      ,>);
Copy the code

2.2.2 Constructor reference

The argument list of the constructor to be called should be consistent with the basic syntax of the argument list of the abstract method in the function interface

  1. Class:: constructor, primitive (x)->new Class(x), can have Huawei Class::new;
    System.out.println("Class:: constructor, primitive (x)->new Class(x), can have Huawei Class::new;);
    // Call the parameterless constructor of ArrayList
    Supplier<List> sup1 = () -> new ArrayList();
    Supplier<List> sup2 = ArrayList::new;
    System.out.println("Class :: constructor, raw () -> new ArrayList()");
    System.out.println("Class :: constructor, optimizes ArrayList::new");

    Public Employe(String name, int age) {}
    BiFunction<String, Integer, Employe> biFunction = (x,y) ->new Employe(x,y);
    BiFunction<String, Integer, Employe> biFunction1 = Employe::new;
    System.out.println("Class :: constructor (x,y) ->new Employe(x,y)");
    System.out.println("Class :: construct method, optimize writing method Employe::new");
Copy the code

1.2.3 Array reference

  1. The array reference format is Type ::new, and the lambda expression is x -> new Type[x], which can be optimized to Type[]::new
    System.out.println("Array reference format Type ::new, lambda expression x -> new Type[x] can be optimized to Type[]::new");
    Function<Integer,String[]> func1 = length -> new String[length];
    Function<Integer,String[]> func2 = String[] :: new;
Copy the code

The complete code logic is as follows:

package com.omg.lambda;

import com.omg.Employe;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.*;

/** * We can use a "method reference" when the content in the body of a Lambda expression is already implemented by a method * The Lambda expression has a list of arguments for the method called in the entity. The return type must be the same as the abstract method in the functional interface * Function reference syntax format: * Object :: instance method * class :: Static method * class :: Instance method * Constructor reference format: * ClassName :: new * * Array reference format: * Type :: new; * /
public class Test2FunctionReference {
    public static void main(String[] args) {
        System.out.println("Lambda expression: a -> x.unction (a) can be simplified to x::function, x is a pre-requested variable");
        PrintStream ps = System.out;
        Consumer<String> con1 = (s) -> ps.println(s);
        con1.accept((s) -> ps.println(s));
        Consumer<String> con2 = ps::println;
        con2.accept("Object :: instance method, optimization write: ps::println");

        System.out.println("");
        System.out.println("Lambda expression: (a,b) -> ClassName. StaticMethod (a,b) can be reduced to ClassName::function");
        BinaryOperator<Integer> max = (x, y) -> Integer.max(x, y);
        BinaryOperator<Integer> max2 = Integer::max;
        System.out.println("Class :: static method, primitive: BinaryOperator
      
        Max = (x, y) -> integer.max (x, y);"
      );
        System.out.println("Class :: static method, optimizer: BinaryOperator
      
        max2 = Integer:: Max;"
      );

        System.out.println("");
        System.out.println("Class :: instance method optimization 1, lambda is (x)->x.method() can be optimized to xClassName::method");
        Function<String, String> upper = x -> x.toUpperCase();
        Function<String, String> upper2 = String::toUpperCase;
        System.out.println(Function
      
        upper = x -> x.topperCase ();
      ,>);
        System.out.println(Function
      
        upper2 = String::toUpperCase;
      ,>);

        System.out.println("");
        System.out.println("Class :: instance method optimization 2, lambda is (x, y)->x.method(y) can be optimized to xClassName::method");
        BiFunction<String, String, Boolean> compare = (x,y) -> x.equals(y);
        BiFunction<String, String, Boolean> compare2 = String::equals;
        System.out.println("Class :: instance method: BiFunction
      
        compare = (x,y) -> x.equals(y);"
      ,>);
        System.out.println("BiFunction
      
        compare2 = String::equals;"
      ,>);

        System.out.println("Class:: constructor, primitive (x)->new Class(x), can have Huawei Class::new;);
        // Call the parameterless constructor of ArrayList
        Supplier<List> sup1 = () -> new ArrayList();
        Supplier<List> sup2 = ArrayList::new;
        System.out.println("Class :: constructor, raw () -> new ArrayList()");
        System.out.println("Class :: constructor, optimizes ArrayList::new");

        Public Employe(String name, int age) {}
        BiFunction<String, Integer, Employe> biFunction = (x,y) ->new Employe(x,y);
        BiFunction<String, Integer, Employe> biFunction1 = Employe::new;
        System.out.println("Class :: constructor (x,y) ->new Employe(x,y)");
        System.out.println("Class :: construct method, optimize writing method Employe::new");

        System.out.println("\n");
        System.out.println("Array reference format Type ::new, lambda expression x -> new Type[x] can be optimized to Type[]::new");
        Function<Integer,String[]> func1 = length -> new String[length];
        Function<Integer,String[]> func2 = String[] :: new; }}Copy the code

2.3. Function interface

2.3.1 Function Interface Definition

  • Lambda expressions require support for “functional interfaces.
  • Functional interface: An interface with only one abstract method in the interface is called a functional interface.
  • You can use the @functionalInterface annotation to check if the interface is functional
  1. Standard functional interface with only one method
/** * 1. A standard functional interface with only one method */
@FunctionalInterface
interface  IsFunctionalInterface{
    void test(a);
}
Copy the code

2. If the interface has multiple functions, it is not a functional interface

/** * 2. This is not a functional interface. A functional interface can only have one method. Multiple non-overriding abstract methods found in interface com.omg.lambda.NoFunctionalInterface */
@FunctionalInterface
interface  NoFunctionalInterface{
    void test(a);
    void test2(a);
}
Copy the code
  1. If you want more than one method in a functional interface, you need to decorate the other methods with default and implement the method default body, leaving only one unimplemented method
@FunctionalInterface
interface  IsFunctionalInterface2{
    void test(a);
    default void test2(a){
        System.out.println("Default-decorated methods need to implement the method body.");
    }
    default void test3(a){
        System.out.println("Default-decorated methods need to implement the method body."); }}Copy the code

2.3.2 Java8 built-in four core functional interfaces

  • Consumer{void accept(T T)} : a Consumer interface has no return value for one argument
  • Supplier{T get()} : Supplier interfaces require no parameters and return values
  • Function

    {R apply(T T)} : Function

    {R apply(T T)
    ,>
    ,>
  • Predicate {Boolean test(T T)}: Predicate interface returns true or false for one argument

Example:

package com.omg.lambda;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

Void accept(T T); void accept(T T); void accept(T T); void accept(T T); * * Supplier
      
        : Supplier interface does not require parameters and returns * T get(); * * Function 
       
        ; * * Function 
        
         ; * * Predicate
         
           : Predicate interface one argument returns true or false * Boolean test(T T); * /
         ,>
       ,>
      
public class Test4DefaultFunctionInterface {
    public static void main(String[] args) {
        Test4DefaultFunctionInterface.TestDefaultFunctionInterface();
    }

    /** test the default functional interface */
    public static void TestDefaultFunctionInterface(a){
        /* Consumer
      
       {void accept(T T)
      
        Consumer<String> consumer = x-> System.out.println(x);
        consumer.accept(
      
       {void accept(T T)};
      );

        /* Supplier
      
       {T get(); } requires no arguments and returns a value */
      
        Supplier<String> supplier = ()->"Supplier
      
       {T get(); }, no parameters are required, return a value"
      ;
        System.out.println(supplier.get());

        Function 
      
       {R apply(T T); } One parameter and one return value */
      ,>
        Function<String, String> function = x -> x;
        System.out.println(function.apply(Function 
      
       {R apply(T T); }, one parameter and one return value"
      ,>));

        Predicate
      
       {Boolean test(T T); /* Predicate
       
        {Boolean test(T T); } One argument returns true or false*/
       
        Predicate<String> predicate = x->{
            System.out.println(x);
            return x==null;
        };
        predicate.test(Predicate
      
       {Boolean test(T T); } one argument returns true or false"
      ); }}Copy the code

2.3.3 Subinterface of the default functional interface

The four default functional interfaces provided by Java are limited, so some extension interfaces are provided.

  1. Consumer subinterface:
    BiConsumer<T, U>{void accept(T var1, U var2); }Copy the code
  1. Function

    subinterface:
    ,>
    BiFunction<T, U, R>{R apply(T var1, U var2); } UnaryOperator<T> extends Function<T, T>{<T>UnaryOperator<T> identity(a)}
    BinaryOperator<T> extends BiFunction<T, T, T>{}
Copy the code
  1. Predicate subinterfaces:
    BiPredicate<T, U> {boolean test(T var1, U var2); }Copy the code
  1. other
    ToIntFunction<T> {int applyAsInt(T var1); } ToIntBiFunction<T, U>{int applyAsInt(T var1, U var2); } ToLongFunction<T> {long applyAsLong(T var1); } ToLongBiFunction<T, U> {long applyAsLong(T var1, U var2); } ToDoubleFunction<T> {double applyAsDouble(T var1); } ToDoubleBiFunction<T, U> {double applyAsDouble(T var1, U var2); } IntFunction<R> {R apply(int var1); } LongFunction<R> {R apply(long var1); } DoubleFunction<R> {R apply(double var1);
Copy the code

3. Stream

Stream is a data channel that manipulates the sequence of elements generated by the data source (list, map). Collection is about data access, stream is about data calculation. Stream has the following characteristics:

  • Stream itself does not store elements
  • The Stream does not change the original object, but instead generates a new Stream that holds the result
  • The Stream is delusively computed, meaning that it is executed only when the result is needed

The complete process consists of three steps:

  • Create a flow
  • In the middle of operation
  • Termination of operations

3.1 create a Stream

  1. You can use stream() or parallelStream() provided by the Collection family of collections (classes that inherit from Collection implement the stream()/parallelStream() method, which can be used to create streams directly)
    // Method 1: A class that inherits Collection implements the stream() method, which can be used to create streams directly
    List<String> list =  new ArrayList<>();
    list.stream(); // Create a serial stream
    list.parallelStream() // Create a parallel stream
        .forEachOrdered(System.out::println); // If a serial stream causes a disorder, use this mode to iterate in order
Copy the code
  1. Get an array stream from the static stream() method of Arrays
    // Method 2: Obtain the stream() from the static stream() method of Arrays
    int[] ints = new int[10];
    Arrays.stream(ints);
Copy the code
  1. Through the static method stream.of () in the Stream class
    // Method 3: via static methods in the Stream class
    Stream<String> stream = Stream.of("aa"."bb"."cc");
Copy the code
  1. Create infinite stream iteration/generation
    // Method 4: Create infinite stream iteration/generation
    / / iteration
    Stream<Integer> iStream = Stream.iterate(0, x->x+1);
    iStream.limit(10).forEach(System.out::println);
    / / generated
    Stream<Double> dStream = Stream.generate(()-> Math.random());
    dStream.limit(10).forEach(System.out::println);
Copy the code

3.2 Stream intermediate operations

Stream Intermediate operations: Multiple intermediate operations can be linked together to form a pipeline. The intermediate operations do not perform any processing unless the termination operation is triggered on the pipeline. When the operation is terminated, all processing is done at once, called lazy evaluation.

3.2.1 Screening and slicing

  1. Filter (): Receives a Lambda to exclude certain elements from the stream
  2. Distinct (): filter that removes duplicate elements through hashcode() and equals() of the elements generated by the stream
  3. Limit (): truncates the stream so that it does not exceed a given number of elements
  4. Skip (long n): Skip elements and return a stream that has dropped the first N elements. If there are fewer than n elements in the stream, an empty stream is returned
 public void test1(a){
    // Filter out employees whose salary is less than 7,000
    System.out.println("Filter (): Takes a Lambda and excludes certain elements from the stream.");
    employees.stream()
            .filter((e)->e.getSalary()>=7000)
            .forEach(System.out::println);

    // Override the hashCode and equals methods
    System.out.println("Distinct (): filter to remove duplicate elements by hashcode() and equals() of elements generated by the stream.");
    employees.stream()
            .distinct()
            .forEach(System.out::println);

    // Limit only has two elements
    System.out.println("Limit (): truncates the stream so that no more than a given number of elements exist.");
    employees.stream()
            .limit(2)
            .forEach(System.out::println);

    // skip the first four elements
    System.out.println("Skip (long n): Skip elements and return a stream that has dropped the first n elements. If there are less than n elements in the stream, an empty stream is returned.);
    employees.stream()
            .skip(4)
            .forEach(System.out::println);
}
Copy the code

The log output is as follows:

filter(): Receiving the Lambda, Employe{name=' Tianqi ', age=18, salary=9999.99} Employe{name=' Tianqi ', age=8, salary=8888.88} Employe{name=' Tianqi ', Age =8, salary=8888.88} Employe{name=' tien-qi ', age=8, salary=8888.88} distinct(): Screening, Employe{name=' li3 ', age=18, salary=9999.99} Employe{name=' li4 ', age=39, Salary =5555.55} Employe{name='王五', age=50, salary=666.99} salary=6666.66} Employe{name='王五', age=16, salary=6666.66} Age = 8, salary = 8888.88} limit () : Employe{name=' li3 ', age=18, salary=9999.99} Salary =5555.55} skip(long n): skip elements and return a stream that drops the first n elements. Employe{name=' Tianqi ', age=8, salary=8888.88} Salary =8888.88} salary= Employe{name=' tian Qi ', age=8, salary=8888.88}Copy the code

3.2.2 mapping

  1. Map (): Takes a function as an argument that is applied to each element and mapped to a new element
  2. MapToDoubel (ToDoubleFunction f): Takes a function as an argument that is applied to each element, producing a new DoubleStream
  3. MapToInt (ToIntFunction f): takes a function as an argument that is applied to each element, producing a new IntStream
  4. MapToLong (ToLongFunction f): takes a function as an argument that is applied to each element, producing a new LongStream
  5. FlatMap (Function f): Takes a Function as an argument, replaces each element in the flow with another one, and links all flows into one
 public void test2(a){
    // Pull out all the names to form a new stream
    System.out.println("Map (): Takes a function as an argument that is applied to each element and maps it to a new element");
    employees.stream()
            .map((e)->e.getName())
            .forEach(System.out::println);

    // Withdraw all wages
    System.out.println("MapToDoubel (ToDoubleFunction f): Takes a function as an argument that is applied to each element, producing a new DoubleStream");
    employees.stream()
            .mapToDouble(e->e.getSalary())
            .forEach(System.out::println);

    // Take all the names and split them into streams according to the character and output
    System.out.println("FlatMap (Function f): Takes a Function as an argument, replaces each element in the stream with another one, and links all the streams into one.");
    employees.stream()
            .map(e->e.getName())
            .flatMap(Test7StreamIntermediateOperations::filterCharacter)
            .forEach(System.out::println);
    System.out.println("Instead of comparing flatmap, output is Stream by Stream. Flatmap combines multiple streams into a single Stream.");
    employees.stream()
            .map(e->e.getName())
            .map(Test7StreamIntermediateOperations::filterCharacter)
            .forEach(System.out::println);

}

public static Stream<Character> filterCharacter(String str){
    List<Character> list = new ArrayList<>();

    for (Character ch : str.toCharArray()) {
        list.add(ch);
    }

    return list.stream();
}
Copy the code

The log output is as follows:

Map (): takes a function as an argument that is applied to each element and maps it to a new element mapToDoubel(ToDoubleFunction f): Take a Function as an argument that will be applied to each element, generating a new DoubleStream 9999.99 5555.55 666.99 6666.66 8888.88 8888.88 8888.88 flatMap(Function f): Take a function as a parameter, replace each element in the Stream with another one, and then link all the streams into a single Stream without using flatmap comparisons. The output is a Stream. FlatMap incorporating multiple streams flow for a Java. Util. Stream. ReferencePipeline $Head @ 9 f70c54 Java. Util. Stream. Bef66 ReferencePipeline $Head @ 234 java.util.stream.ReferencePipeline$Head@737996a0 java.util.stream.ReferencePipeline$Head@61dc03ce java.util.stream.ReferencePipeline$Head@50f8360d java.util.stream.ReferencePipeline$Head@2cb4c3ab java.util.stream.ReferencePipeline$Head@13c78c0bCopy the code

3.2.3 sorting

  1. Sorted (): Generates a new stream that is sorted in natural order
  2. Sorted (Comparator comp): Generates a new stream that is sorted in Comparator order
public void  test3(a){
    // Pay rank
    System.out.println("Sorted (): generates a new stream in which sorted in natural order");
    employees.stream()
            .mapToDouble(Employe::getSalary)
            .sorted()
            .forEach(System.out::println);

    // Sort by age and output the employees object instead of just the age
    System.out.println("Sorted (Comparator comp): Generates a new stream that is sorted in Comparator order.");
    employees.stream()
            .sorted((x,y)->x.getAge()-y.getAge())
            .forEach(System.out::println);
}
Copy the code

The log output is as follows:

Sorted (): generates a new stream that is sorted in natural order 666.99 5555.55 6666.66 8888.88 8888.88 8888.88 9999.99 sorted(Comparator comp): Employe{name=' Tianqi ', age=8, salary=8888.88} Employe{name=' Tianqi ', age=8, Salary =8888.88} Employe{name=' Tian Qi ', age=8, salary=8888.88} Employe{name=' Zhao vi ', age=16, salary=6666.66} Employe{name=' Zhang SAN ', Employe{name=' Employe ', age=39, salary=5555.55} Age =50, salary=666.99}Copy the code

The complete code is as follows:

package com.omg.lambda;

import com.omg.Employe;

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

/** * Stream: multiple intermediate operations can be linked together to form a pipeline, unless the pipeline triggers the termination of the operation, the intermediate operations do not perform any processing, and when the termination of the operation is processed at once, called lazy: Accept Lambda to exclude certain elements from the stream * DISTINCT (): filter to remove duplicate elements by hashcode() and equals() of the elements generated by the stream * limit(): Skip (long n): Skip the elements and return a stream that has dropped the first n elements. If there are fewer than n elements in the stream, an empty stream is returned * * map: * map(): Takes a function as an argument that is applied to each element and maps it to a new element * mapToDoubel(ToDoubleFunction f): Take a function as an argument that will be applied to each element, producing a new DoubleStream * mapToInt(ToIntFunction f): IntStream * mapToLong(ToLongFunction f); IntStream * mapToLong(ToLongFunction f); LongStream * flatMap(Function f): Take a Function as an argument that replaces each element in the stream with another one, and then link all the streams into one stream * sort: * sorted(): Generates a new stream in which it is sorted in natural order * sorted(Comparator comp): generates a new stream in which it is sorted in Comparator order */
public class Test7StreamIntermediateOperations {
    List<Employe> employees = Arrays.asList(
            new Employe("Zhang".18.9999.99),
            new Employe("Bill".39.5555.55),
            new Employe("Fifty".50.666.99),
            new Employe("Daisy".16.6666.66),
            new Employe("Cropland 7".8.8888.88),
            new Employe("Cropland 7".8.8888.88),
            new Employe("Cropland 7".8.8888.88));/** * Filter and slice: * filter(): receives Lambda and excludes certain elements from the stream * distinct(): filters to remove duplicate elements by hashcode() and equals() of the generated elements in the stream * limit(): Skip (long n): Skip the elements and return a stream that has dropped the first n elements. If there are fewer than n elements in the stream, an empty stream */ is returned
    public void test1(a){
        // Filter out employees whose salary is less than 7,000
        System.out.println("Filter (): Takes a Lambda and excludes certain elements from the stream.");
        employees.stream()
                .filter((e)->e.getSalary()>=7000)
                .forEach(System.out::println);

        // Override the hashCode and equals methods
        System.out.println("Distinct (): filter to remove duplicate elements by hashcode() and equals() of elements generated by the stream.");
        employees.stream()
                .distinct()
                .forEach(System.out::println);

        // Limit only has two elements
        System.out.println("Limit (): truncates the stream so that no more than a given number of elements exist.");
        employees.stream()
                .limit(2)
                .forEach(System.out::println);

        // skip the first four elements
        System.out.println("Skip (long n): Skip elements and return a stream that has dropped the first n elements. If there are less than n elements in the stream, an empty stream is returned.);
        employees.stream()
                .skip(4)
                .forEach(System.out::println);
    }

    /** * mapping: * map(): takes a function as an argument that is applied to each element and maps it to a new element * mapToDoubel(ToDoubleFunction f): Take a function as an argument that will be applied to each element, producing a new DoubleStream * mapToInt(ToIntFunction f): IntStream * mapToLong(ToLongFunction f); IntStream * mapToLong(ToLongFunction f); LongStream * flatMap(Function f): Take a Function as an argument that replaces each element in the stream with another one, and then link all the streams into one stream */
    public void test2(a){
        // Pull out all the names to form a new stream
        System.out.println("Map (): Takes a function as an argument that is applied to each element and maps it to a new element");
        employees.stream()
                .map((e)->e.getName())
                .forEach(System.out::println);

        // Withdraw all wages
        System.out.println("MapToDoubel (ToDoubleFunction f): Takes a function as an argument that is applied to each element, producing a new DoubleStream");
        employees.stream()
                .mapToDouble(e->e.getSalary())
                .forEach(System.out::println);

        // Take all the names and split them into streams according to the character and output
        System.out.println("FlatMap (Function f): Takes a Function as an argument, replaces each element in the stream with another one, and links all the streams into one.");
        employees.stream()
                .map(e->e.getName())
                .flatMap(Test7StreamIntermediateOperations::filterCharacter)
                .forEach(System.out::println);
        System.out.println("Instead of comparing flatmap, output is Stream by Stream. Flatmap combines multiple streams into a single Stream.");
        employees.stream()
                .map(e->e.getName())
                .map(Test7StreamIntermediateOperations::filterCharacter)
                .forEach(System.out::println);

    }

    public static Stream<Character> filterCharacter(String str){//add(Object obj) addAll(Collection coll)
        List<Character> list = new ArrayList<>();

        for (Character ch : str.toCharArray()) {
            list.add(ch);
        }

        return list.stream();
    }

    /** * Sort: * sorted(): generates a new stream where sorted in natural order * sorted(Comparator comp): generates a new stream where sorted in Comparator order */
    public void  test3(a){
        // Pay rank
        System.out.println("Sorted (): generates a new stream in which sorted in natural order");
        employees.stream()
                .mapToDouble(Employe::getSalary)
                .sorted()
                .forEach(System.out::println);

        // Sort by age and output the employees object instead of just the age
        System.out.println("Sorted (Comparator comp): Generates a new stream that is sorted in Comparator order.");
        employees.stream()
                .sorted((x,y)->x.getAge()-y.getAge())
                .forEach(System.out::println);
    }

    public static void main(String[] args) {
        Test7StreamIntermediateOperations test7StreamIntermediateOperations = newTest7StreamIntermediateOperations(); test7StreamIntermediateOperations.test1(); test7StreamIntermediateOperations.test2(); test7StreamIntermediateOperations.test3(); }}Copy the code

3.3 Terminating Operations

3.3.1 Search and Match:

  1. AllMatch – checks to match all elements
  2. AnyMatch – Checks whether at least one element is matched
  3. NoneMatch – Checks to see if all elements are not matched
  4. FindAny — Returns any element in the current stream
  5. Count — Returns the total number of elements in the stream
  6. Max — Returns the maximum value in the stream
  7. Min – Returns the minimum value in the stream
private void testMax(a) {
    Optional<Employe> min = employees.stream().max((x, y) -> x.getAge() - y.getAge());
    System.out.println("Max acquires the oldest employee:" + min.get().toString());
}

private void testMin(a) {
    Optional<Employe> min = employees.stream().min((x, y) -> x.getAge() - y.getAge());
    System.out.println("Min obtains the youngest employee:" + min.get().toString());
}

private void testCount(a) {
    long count = employees.stream().count();
    System.out.println("Count Counts the number of employees:" + count);
}

private void testFindAny(a) {
    Optional<Employe> any = employees.stream().findAny();
    System.out.println("FindAny randomly obtains information about an employee:" + any.get().toString());
}

private void testNoneMatch(a) {
    boolean noneMatch = employees.stream().noneMatch(e->e.getSalary()>10000);
    System.out.println("NoneMatch determines if wages are all less than 10,000:" + noneMatch);
}

private void testAnyMatch(a) {
    boolean anyMatch = employees.stream()
            .anyMatch(e->e.getSalary()>5000);
    System.out.println("AnyMatch determines whether the salary is greater than 5000:" + anyMatch);
}

private void testAllMatch(a) {
    boolean allMatch = employees.stream()
            .allMatch(e->e.getSalary()>5000);
    System.out.println("AllMatch determines whether all salaries are greater than 5000:" + allMatch);

}
Copy the code

The log output is as follows:

AllMatch determines whether all salaries are greater than 5000: false anyMatch determines whether all salaries are greater than 5000: true noneMatch Determines whether all salaries are less than 10000: true findAny randomly gets an employee information: Employe{name=' three ', age=18, salary=9999.99} count Number of employees: 7 Max Obtain the oldest employee: Employe{name=' Wang Wu ', age=50, salary=666.99} minCopy the code

3.3.2 rainfall distribution on 10-12 reduction

You can repeatedly combine elements ina stream to obtain a value identity starting value BinaryOperator binary operation

  1. reduce(T identity, BinaryOperator)
  2. reduce(BinaryOperator)
private void testReduce(a) {
    String reduce = employees.stream().map(Employe::getName).reduce("Name statistics :", (x, y) -> x + y);
    System.out.println("Reduce calculates the names of all employees :" + reduce);
    Optional<Double> reduce1 = employees.stream().map(Employe::getSalary).reduce(Double::sum);
    System.out.println("Reduce calculates the salaries of all employees and:" + reduce1.get());
}
Copy the code

Log information is as follows:

Reduce calculates the names of all employees: Name statistics: Zhang, Li, 4, Wang, 5, Zhao, 6, Tian, qi, Tian, Qi reduce calculates the salaries of all employees: 49555.829999999994Copy the code

3.3.3 Collector interface

The implementation of the methods in the Collector interface determines how the flow is collected (for example, to a List, Set, Map). But the Collectors utility class provides a number of static methods that make it easy to create common collector instances

package com.omg.lambda;

import com.omg.Employe;

import java.util.*;
import java.util.stream.Collectors;

/** * Terminate operations * Collector interface: * The implementation of the methods in the Collector interface determines how the collection operations (such as collecting to a List, Set, Map) are performed on the stream. * But the Collectors utility class provides a number of static methods that make it easy to create common collector instances */
public class Test9StreamCollect {
    List<Employe> employees = Arrays.asList(
            new Employe("Zhang".18.9999.99),
            new Employe("Bill".39.5555.55),
            new Employe("Fifty".50.666.99),
            new Employe("Daisy".16.6666.66),
            new Employe("Cropland 7".8.8888.88),
            new Employe("Cropland 7".40.8888.88),
            new Employe("Cropland 7".60.8888.88));private void testJoin(a) {
        String str = employees.stream()
                .map(Employe::getName)
                .collect(Collectors.joining(","."# # #"."# # #"));
        System.out.println("Collections. Joining () connect all the elements, and before the suffix '# # #' middle ', 'segmentation:" + str);
    }

    // Multilevel grouping
    public void testGroupingBy2(a){
        Map<String, Map<String, List<Employe>>> map = employees.stream()
                .collect(Collectors.groupingBy(Employe::getName, Collectors.groupingBy((e) -> {
                    if (e.getAge() <= 35) {
                        return "Youth";
                    } else if (e.getAge() <= 50) {
                        return "Middle-aged";
                    } else {
                        return "Old age"; }}))); System.out.println("Multilevel groupingBy() can be implemented");
        System.out.println("Multilevel grouping by element name and age group:" + map);
    }

    / / group
    public void testGroupingBy(a){
        Map<String, List<Employe>> map = employees.stream()
                .collect(Collectors.groupingBy(Employe::getName));
        System.out.println("Collectors.groupingBy() 将元素分组");
        System.out.println("Group by element name:" + map);
    }

    public void testPartitioningBy(a){
        Map<Boolean, List<Employe>> map = employees.stream()
                .collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
        System.out.println("Collectors. PartitioningBy () flow elements can be divided into two groups, meet the conditions for a set and does not meet the conditions of a set of");
        System.out.println("All employees are separated by the salary line of 8000:" + map);
    }

    public void testSummarizingDouble(a){
        DoubleSummaryStatistics dss = employees.stream()
                .collect(Collectors.summarizingDouble(Employe::getSalary));
        System.out.println("Collectors. SummarizingDouble for statistical information.");
        System.out.println("Total wages of employees:" + dss.getSum());
        System.out.println("Average salary of employees:" + dss.getAverage());
        System.out.println("Maximum employee salary:" + dss.getMax());
    }

    public void testSummarizing(a){
        // Count elements
        Long count= employees.stream().collect(Collectors.counting());
        System.out.println("Counting the number of elements with the number of employees is:" + count);

        / / the mean
        Double avg= employees.stream().collect(Collectors.averagingDouble(Employe::getSalary));
        System.out.println("Collectors. AveragingDouble () statistical average, staff average wages is:" + avg);

        / / the sum
        Double sum= employees.stream().collect(Collectors.summingDouble(Employe::getSalary));
        System.out.println("Collectors. SummingDouble () the sum of the salaries of the employees is:" + sum);

        // The maximum number of employees
        Optional<Employe> max = employees.stream()
                .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println("Collectors. MaxBy () obtain the maximum and the highest paid employee is:" + max.get());

        / / the minimum
        Optional<Double> min = employees.stream().map(Employe::getSalary).collect(Collectors.minBy(Double::compare));
        System.out.println("Collectors. MinBy () gets the minimum value, and the minimum wage among employees is:" + min.get());
    }

    public void testToCollect(a){
        List<String> list = employees.stream().map(Employe::getName).collect(Collectors.toList());
        System.out.println("Items.tolist () converts the stream to a list:" + list);

        Set<String> set = employees.stream().map(Employe::getName).collect(Collectors.toSet());
        System.out.println("Tallers.toset () converts the stream to a set:" + set);

        HashSet<String> hashSet = employees.stream().map(Employe::getName).collect(Collectors.toCollection(HashSet::new));
        System.out.println("Collectors. ToCollection () specifies the Collect type to which the stream is converted, which in this case is converted to HashSet:" + hashSet);
    }

    public static void main(String[] args) {
        Test9StreamCollect test9StreamCollect = newTest9StreamCollect(); test9StreamCollect.testJoin(); test9StreamCollect.testSummarizingDouble(); test9StreamCollect.testPartitioningBy(); test9StreamCollect.testGroupingBy(); test9StreamCollect.testGroupingBy2(); test9StreamCollect.testSummarizing(); test9StreamCollect.testToCollect(); }}Copy the code

The log output is as follows:

Collections. Joining () connect all the elements, and before the suffix '# # #' middle ', 'segmentation: # # # zhang SAN, li si, Cathy, Daisy, panax notoginseng and panax notoginseng, cropland 7 # # # Collectors. SummarizingDouble statistical information: Total salary: 49555.83 Average salary: 7079.404285714286 Maximum salary: 9999.99 Collectors. PartitioningBy () flow elements can be divided into two groups, meet the conditions for a set and does not meet the conditions of a set of all employees according to pay 8000 to separate: Employe{name=' Employe ', age=39, salary=5555.55}, Employe{name=' Employe ', age=50, salary=666.99}, Age =16, salary=6666.66}], age=18, salary=9999.99}, age=8, salary=8888.88}, Employe{name=' Tianqi ', age=40, salary=8888.88}, Employe{name=' Tianqi ', age=60, Salary =8888.88}]} collagers.groupingby () Employe =[Employe{name=' Employe ', age=39, salary=5555.55}], Employe =[Employe{name=' Employe ', age=50, salary=666.99}], Employe =[Employe{name=' Employe ', age=16, salary=6666.66}], Age =8, salary=8888.88}, age=40, salary=8888.88}, age=60, Salary =8888.88}]} collagers.groupingby () Middle-aged = {li si = {[Employe {name = 'bill', the age = 39, salary = 5555.55}]}, threes = {youth = [Employe {name = 'Joe', the age = 18, salary = 9999.99}]}. Fifty = {middle-aged = [Employe {name = 'Cathy', the age = 50, salary = 666.99}]}, zhao six = {youth = [Employe {name = 'Daisy miller, the age = 16, salary = 6666.66}]}. Employe =[Employe{name=' Tianqi ', age=8, salary=8888.88}], Middle-age =[Employe{name=' Tien-qi ', age=40, salary=8888.88}]}} 2000.counting () Count the number of elements. The number of employees is: 7 Collectors. AveragingDouble statistical average (), the staff average wages are: 7079.404285714286 Collectors. SummingDouble statistical sum (), staff salary sum to: 49555.83 Collectors. MaxBy () obtain the maximum value and the highest paid employee is: Employe{name=' zhang three ', age=18, salary=9999.99} Collectors. MinBy () obtain the minimum value and the minimum wage among employees is: 666.99. [Zhang SAN, Li Si, Wang Wu, Zhao Liu, Tian Qi, Tian Qi, Tian Qi, Tian Qi, Et al. () Convert a stream to a set: [Li Si, Zhang SAN, Wang Wu, Zhao Liu, Tian Qi] Collectors. ToCollection () specifies the collector type to which the flow is converted. In this case, it is converted to HashSet: [Li Si, Zhang SAN, Wang Wu, Zhao Liu, Tian Qi]Copy the code