18, What's new in JAVA8

Posted by melefire on Wed, 05 Jan 2022 19:01:58 +0100

1. JAVA overview

  • Java 8 (also known as jdk 1.8) is a major version of Java language development.
  • Java 8 was released by oracle in March 2014 and can be regarded as the most revolutionary version since Java 5. Java 8 brings a lot of new features to the Java language, compiler, class library, development tools and JVM.

2. Benefits of new features in Java 8

  • Faster
  • Less code (new syntax added: Lambda expression)
  • Powerful Stream API
  • Easy parallel
  • Minimize null pointer exceptions: Optional
  • Nashorn engine, which allows JS applications to run on the JVM

3. Parallel stream and serial stream

Parallel flow is to divide a content into multiple data blocks and process each data block with different threads. Compared with serial streams, parallel streams can greatly improve the execution efficiency of programs.

Java 8 optimizes parallelism, and we can easily operate data in parallel. The Stream API can declaratively switch between parallel and sequential streams through parallel() and sequential().

4. Lambda expression

Lambda is an anonymous function. We can understand lambda expression as a piece of code that can be passed (pass the code like data). Using it, you can write more concise and flexible code. As a more compact code style, the language expression ability of Java has been improved.

4.1 example of lambda expression

package week4.day28;

import org.junit.Test;

import java.util.Comparator;

/**
 * @author zhunter
 * @create 2021-12-31-10:57
 *
 * Lambda Examples of expressions
 */
public class LambdaTest {
    @Test
    public void test1() {
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello,world");
            }
        };

        r1.run();

        System.out.println("******************************");

        Runnable r2 = () -> System.out.println("hello,world");

        r2.run();
    }

    @Test
    public void test2() {
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };

        int compare1 = com1.compare(12,21);
        System.out.println(compare1);

        System.out.println("******************************");

        //How to write Lambda expressions
        Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1,o2);

        int compare2 = com2.compare(123,21);
        System.out.println(compare2);

        System.out.println("******************************");

        //Method reference
        Comparator<Integer> com3 = Integer :: compare;

        int compare3 = com3.compare(123,123);
        System.out.println(compare3);
    }
}

4.2 use of lambda expression syntax

package week4.day28;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.function.Consumer;

/**
 * @author zhunter
 * @create 2021-12-31-11:11
 *
 * Lambda Use of expressions
 *
 * 1.For example: (O1, O2) - > integer compare(o1,o2);
 * 2.Format:
 *      -> :lambda Operator or arrow operator
 *      ->Left: lambda parameter list (actually the parameter list of abstract methods in the interface)
 *      ->Right: lambda body (actually the method body of the overridden abstract method)
 *
 * 3.Lambda Use of expressions: (divided into 6 Introductions)
 *
 *  Summary:
 *  ->Left: the parameter type of Lambda parameter list can be omitted (type inference); If the Lambda parameter list has only one parameter, its pair () can also be omitted
 *  ->Right: Lambda body should use a pair of {} packages; If the Lambda body has only one execution statement (possibly a return statement), the pair of {} and return keywords can be omitted
 *
 * 4.Lambda The essence of expressions: as instances of functional interfaces
 *
 * 5.If only one abstract method is declared in an interface, the interface is called a functional interface. We can use one interface
 * Use the @ functional interface annotation on to check whether it is a functional interface
 *
 * 6.Therefore, those previously expressed by anonymous implementation classes can now be written in Lambda expressions
 */
public class LambdaTest1 {
    //Syntax format 1: no parameter, no return value
    @Test
    public void test1() {
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello,world");
            }
        };

        r1.run();

        System.out.println("******************************");

        Runnable r2 = () -> {
            System.out.println("hello,world");
        };

        r2.run();
    }

    //Syntax format 2: Lambda needs a parameter, but there is no return value
    @Test
    public void test2() {
        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("lie");

        System.out.println("******************************");

        Consumer<String> con1 = (String s) -> {
            System.out.println(s);
        };
        con1.accept("oath");
    }

    //Syntax format 3: data types can be omitted because they can be inferred by the compiler, which is called "type inference"
    @Test
    public void test3() {
        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("lie");

        System.out.println("******************************");

        Consumer<String> con1 = (s) -> {
            System.out.println(s);
        };
        con1.accept("oath");
    }

    @Test
    public void test4() {
        ArrayList<String> list = new ArrayList<>();//Type inference

        int[] arr = {1,2,3};
    }

    //Syntax format 4: if Lambda only needs one parameter, the parentheses of the parameter can be omitted
    @Test
    public void test5() {
        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("lie");

        System.out.println("******************************");

        Consumer<String> con1 = s -> {
            System.out.println(s);
        };
        con1.accept("oath");
    }

    //Syntax format 5: Lambda requires two or more parameters, multiple execution statements, and can be returned by
    @Test
    public void test6() {
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };

        System.out.println(com1.compare(12,21));

        System.out.println("******************************");

        Comparator<Integer> com2 = (o1,o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };

        System.out.println(com2.compare(12,21));
    }

    //Syntax format 6: when there is only one statement in Lambda body, return and braces, if any, can be omitted
    @Test
    public void test7() {
        Comparator<Integer> com = (o1,o2) -> o1.compareTo(o2);

        System.out.println(com.compare(12,21));
    }
}

package week4.day28;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * @author zhunter
 * @create 2021-12-31-13:07
 *
 * java Built in 4 core functional interfaces
 *
 * Consumer < T > void accept (T)
 * Supplier < T > t get ()
 * Function < T, R > R apply (T, t)
 * Predicate < T > Boolean test (T)
 */
public class LambdaTest2 {
    public void happyTime(double money, Consumer<Double> con) {
        con.accept(money);
    }

    @Test
    public void test1() {
        happyTime(500, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("The price spent is"+aDouble);
            }
        });

        System.out.println("******************************");

        happyTime(500,money -> System.out.println("Price"+money));
    }

    //Filter the strings in the collection according to the given rule, which is determined by the predict method
    public List<String> filterString(List<String> list, Predicate<String> pre) {
        ArrayList<String> filterList = new ArrayList<>();

        for (String s: list) {
            if (pre.test(s)) {
                filterList.add(s);
            }
        }

        return filterList;
    }

    @Test
    public void test2() {
        List<String> list = Arrays.asList("Beijing","Nanjing","Tianjin");
        List<String> filterStr = filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("Beijing");
            }
        });

        System.out.println(filterStr);

        System.out.println("******************************");

        List<String> filterStr1 = filterString(list,s->s.contains("Beijing"));

        System.out.println(filterStr1);
    }
}

5. Function al interface

5.1 introduction to functional interface

package week4.day28;

/**
 * @author zhunter
 * @create 2021-12-31-11:40
 */
@FunctionalInterface
public interface MyInterface {
    void method1();

//    void method2();
}

  • In Java util. The function package defines the rich functional interfaces of Java 8
  • Java has been advocating "everything is object" since its birth. In Java, object-oriented (OOP) programming is everything. However, with the rise of python, scala and other languages and the challenges of new technologies, Java has to make adjustments to support a wider range of technical requirements, that is, Java can support not only OOP but also OOF (function oriented programming)
  • In functional programming languages, functions are treated as first-class citizens. In programming languages that treat functions as first-class citizens, the type of Lambda expression is function. But in Java 8, it's different. In Java 8, Lambda expressions are objects, not functions. They must be attached to a special object type - functional interface.
  • Simply put, in Java 8, Lambda expressions are instances of functional interfaces. This is the relationship between Lambda expressions and functional interfaces. That is, as long as an object is an instance of a functional interface, the object can be represented by a Lambda expression.
  • Therefore, those previously expressed by anonymous implementation classes can now be written in Lambda expressions.

5.2 introduction and use examples of Java built-in functional interface

Functional interfaceParameter typeReturn typepurpose
Consumer consumer interfaceTvoidApply operations to objects of type T, including methods: void accept (T)
Supplier supply interfacenothingTReturns an object of type T, including the method: T get()
Function < T, R > functional interfaceTRApplies an operation to an object of type T and returns a result. The result is an object of type R. Include method: R apply (T)
Predicate type interfaceTbooleanDetermines whether an object of type T satisfies a constraint and returns a boolean value. Including method: boolean test (T)
BiFunction<T,U,R>T, URApply operations to parameters of type T and u and return results of type R. The inclusion method is: rapply (T, T,U);
UnaryOperator(Function sub interface)TTPerforms a unary operation on an object of type T and returns the result of type T. Including methods: tapply (T);
BinaryOperator(BiFunction sub interface)T,TTPerforms a binary operation on an object of type T and returns the result of type T. Including methods: Tapply(T t1,T t2);
BiConsumer<T,U>T,UvoidApply operations to parameters of type T,U. Including methods: void acept (TT, Uu)
BiPredicate<T,U>T,UbooleanIncluding methods: Boolean test (TT, Uu)
ToIntFunctionTintFunction to calculate int value
ToLongFunctionTlongFunction to calculate the value of long
ToDoubleFunctionTdoubleFunction to calculate the value of double
IntFunctionintRFunction with int argument
LongFunctionlongRFunction with parameter of type long
DoubleFunctiondoubleRFunction with parameter of type double
package week4.day28;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * @author zhunter
 * @create 2021-12-31-13:07
 *
 * java Built in 4 core functional interfaces
 *
 * Consumer < T > void accept (T)
 * Supplier < T > t get ()
 * Function < T, R > R apply (T, t)
 * Predicate < T > Boolean test (T)
 */
public class LambdaTest2 {
    public void happyTime(double money, Consumer<Double> con) {
        con.accept(money);
    }

    @Test
    public void test1() {
        happyTime(500, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("The price spent is"+aDouble);
            }
        });

        System.out.println("******************************");

        happyTime(500,money -> System.out.println("Price"+money));
    }

    //Filter the strings in the collection according to the given rule, which is determined by the predict method
    public List<String> filterString(List<String> list, Predicate<String> pre) {
        ArrayList<String> filterList = new ArrayList<>();

        for (String s: list) {
            if (pre.test(s)) {
                filterList.add(s);
            }
        }

        return filterList;
    }

    @Test
    public void test2() {
        List<String> list = Arrays.asList("Beijing","Nanjing","Tianjin");
        List<String> filterStr = filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("Beijing");
            }
        });

        System.out.println(filterStr);

        System.out.println("******************************");

        List<String> filterStr1 = filterString(list,s->s.contains("Beijing"));

        System.out.println(filterStr1);
    }
}

6. Method reference and constructor reference

  • When the operation to be passed to the Lambda body already has an implemented method, you can use the method reference!
  • Method reference can be regarded as a deep expression of Lambda expression. In other words, a method reference is a Lambda expression, that is, an instance of a functional interface. Pointing to a method by its name can be regarded as a syntax sugar of a Lambda expression.
  • Requirement: the parameter list and return value type of the abstract method implementing the interface must be consistent with the parameter list and return value type of the method referenced by the method!
  • Format: use the operator "::" to separate the class (or object) from the method name.
  • There are three main uses:
    • Object:: instance method name
    • Class:: static method name
    • Class:: instance method name

6.1 method reference

package week4.day28;

/**
 * @author zhunter
 * @create 2021-12-31-13:33
 */

public class Employee {

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

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public double getSalary() {
        return salary;
    }

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

    public Employee() {
        System.out.println("Employee().....");
    }

    public Employee(int id) {
        this.id = id;
        System.out.println("Employee(int id).....");
    }

    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public Employee(int id, String name, int age, double salary) {

        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee{" + "id=" + id + ", 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;

        Employee employee = (Employee) o;

        if (id != employee.id)
            return false;
        if (age != employee.age)
            return false;
        if (Double.compare(employee.salary, salary) != 0)
            return false;
        return name != null ? name.equals(employee.name) : employee.name == null;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = id;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + age;
        temp = Double.doubleToLongBits(salary);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
}


package week4.day28;

import org.junit.Test;

import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author zhunter
 * @create 2021-12-31-13:35
 *
 * Use of method references
 *
 * 1.Usage context: when the operation to be passed to the Lambda body already has an implemented method, you can use the method reference!
 *
 * 2.Method reference is essentially a Lambda expression, which is used as an instance of a functional interface. therefore
 *   Method reference is also an instance of a functional interface.
 *
 * 3. Use format: class (or object):: method name
 *
 * 4. There are three situations as follows:
 *    Case 1 object:: non static method
 *    Case 2: static method
 *
 *    Case 3: non static method
 *
 * 5. Requirements for method reference: the formal parameter list and return value type of the abstract method in the interface are required to be the same as those of the method referenced by the method
 *    The formal parameter list and return value types are the same! (for cases 1 and 2)
 */

public class MethodRefTest {
    // Case 1: object: instance method
    //Void accept in Consumer
    //Void println in PrintStream
    @Test
    public void test() {
        Consumer<String> con1 = str -> System.out.println(str);
        con1.accept("Beijing");

        System.out.println("******************************");

        PrintStream ps = System.out;
        Consumer<String> con2 = ps::println;
        con2.accept("beijing");
    }

    //T get() in Supplier
    //String getName() in Employee
    @Test
    public void test2() {
        Employee employee = new Employee(1001,"zzy",20,10000);

        Supplier<String> sup1 = () -> employee.getName();
        System.out.println(sup1.get());

        System.out.println("******************************");

        Supplier<String> sup2 = employee::getName;
        System.out.println(sup2);
    }

    // Case 2: Class: static method
    //Int compare in Comparator (t T1, t T2)
    //Int compare in Integer (t T1, t T2)
    @Test
    public void test3() {
        Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
        System.out.println(com1.compare(12,21));

        System.out.println("******************************");

        Comparator<Integer> com2 = Integer::compare;
        System.out.println(com2.compare(21,12));
    }

    //R apply in Function (T)
    //Long round(Double d) in Math
    @Test
    public void test4() {
        Function<Double,Long> func = new Function<Double, Long>() {
            @Override
            public Long apply(Double aDouble) {
                return Math.round(aDouble);
            }
        };

        System.out.println("******************************");

        Function<Double,Long> func1 = d -> Math.round(d);
        System.out.println(func1.apply(12.3));

        System.out.println("******************************");

        Function<Double,Long> func2 = Math::round;
        System.out.println(func2.apply(12.3));
    }

    // Case 3: Class: instance method (difficult)
    // Int comapre in Comparator (t T1, t T2)
    // Int T1 in String compareTo(t2)
    @Test
    public void test5() {
        Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
        System.out.println(com1.compare("abc","abd"));

        System.out.println("******************************");

        Comparator<String> com2 = String::compareTo;
        System.out.println(com2.compare("abc","abd"));
    }

    //Boolean test in BiPredicate (t T1, t T2);
    //Boolean T1 in String equals(t2)
    @Test
    public void test6() {
        BiPredicate<String,String> pre1 = (s1,s2) -> s1.contentEquals(s2);
        System.out.println(pre1.test("abc","abd"));

        System.out.println("******************************");

        BiPredicate<String,String> pre2 = String::equals;
        System.out.println(pre2.test("abc","abd"));
    }

    // R apply in Function (T)
    // String getName() in Employee;
    @Test
    public void test7() {
        Employee employee = new Employee(1001,"zzy",20,10000);

        Function<Employee,String> func1 = e -> e.getName();
        System.out.println(func1.apply(employee));

        System.out.println("******************************");

        Function<Employee,String> func2 = Employee::getName;
        System.out.println(func2.apply(employee));
    }
}

6.2 use of constructor reference and array reference

Format: ClassName::new

Combined with functional interface, it is automatically compatible with methods in functional interface.

The constructor reference can be assigned to the defined method. The constructor parameter list should be consistent with the parameter list of the abstract method in the interface! And the return value of the method is the object of the corresponding class of the constructor.

package week4.day28;

import org.junit.Test;

import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author zhunter
 * @create 2021-12-31-14:05
 *
 * 1, Constructor reference
 *      Similar to method references, the formal parameter list of abstract methods of functional interfaces is consistent with that of constructors.
 *      The return value type of the abstract method is the type of the class to which the constructor belongs
 *
 * 2, Array reference
 *     The array can be regarded as a special class, and the writing method is consistent with the constructor reference
 */
public class ConstructorRefTest {
    //Constructor reference
    //T get() in Supplier
    //Empty parameter constructor for Employee: Employee()
    @Test
    public void test() {
        Supplier<Employee> sup = new Supplier<Employee>() {
            @Override
            public Employee get() {
                return new Employee();
            }
        };
        System.out.println(sup.get());

        System.out.println("******************************");

        Supplier<Employee> sup1 = () -> new Employee();
        System.out.println(sup1.get());

        System.out.println("******************************");

        Supplier<Employee> sup2 = Employee::new;
        System.out.println(sup2.get());
    }

    //R apply in Function (T)
    @Test
    public void test2() {
        Function<Integer,Employee> func1 = id ->new Employee(id);
        Employee employee1 = func1.apply(1001);
        System.out.println(employee1);

        System.out.println("******************************");

        Function<Integer,Employee> func2 = Employee::new;
        Employee employee2 = func2.apply(1001);
        System.out.println(employee2);
    }

    //R apply (T, t, u, U) in BiFunction
    @Test
    public void test3() {
        BiFunction<Integer,String,Employee> func1 = (id, name) -> new Employee(id,name);
        System.out.println(func1.apply(1001,"zzy"));

        System.out.println("******************************");

        BiFunction<Integer,String,Employee> func2 = Employee::new;
        System.out.println(func2.apply(1001,"zzy"));
    }

    //Array reference
    //R apply in Function (T)
    @Test
    public void test4() {
        Function<Integer,String[]> func1 = Length -> new String[Length];
        String[] arr1 = func1.apply(5);
        System.out.println(Arrays.toString(arr1));

        System.out.println("******************************");

        Function<Integer,String[]> func2 = String[]::new;
        String[] arr2 = func1.apply(5);
        System.out.println(Arrays.toString(arr2));
    }
}

7. Powerful Stream API

7.1 overview of stream API

  • There are two of the most important changes in Java 8. The first is a Lambda expression; The other is the Stream API.
  • The Stream API (Java. Util. Stream) introduces a true functional programming style into Java. This is the best supplement to the Java class library so far, because the Stream API can greatly provide the productivity of Java programmers and enable programmers to write efficient, clean and concise code.
  • Stream is a key abstract concept for processing collections in Java 8. It can specify the operations you want to perform on collections, and can perform very complex operations such as finding, filtering and mapping data. Using the Stream API to operate on the collection data is similar to a database query executed using SQL. You can also use the Stream API to perform operations in parallel. In short, the Stream API provides an efficient and easy-to-use way to process data.
  • Why use the Stream API
    • In actual development, most data sources in the project come from Mysql, Oracle, etc. But now there are more data sources, such as MongDB and Radis, and these NoSQL data need to be processed at the Java level.
    • The difference between Stream and Collection: Collection is a static memory data structure, while Stream is about calculation. The former is mainly memory oriented and stored in memory, while the latter is mainly CPU oriented and realizes computing through CPU.
/**
 * 1.Stream Focus on the operation of data and dealing with CPU
 *   Collections focus on the storage of data and deal with memory
 *
 * 2.
 * ①Stream You don't store elements yourself.
 * ②Stream The source object will not be changed. Instead, they return a new Stream that holds the result.
 * ③Stream The operation is delayed. This means they wait until they need results
 *
 * 3.Stream Execution process
 * ① Stream Instantiation of
 * ② A series of intermediate operations (filtering, mapping,...)
 * ③ Terminate operation
 *
 * 4.explain:
 * 4.1 An intermediate operation chain that processes the data of the data source
 * 4.2 Once the termination operation is performed, the intermediate operation chain is executed and the results are generated. After that, it will not be used again
 */

7.2 instantiation of stream

EmployeeData class

package week4.day28;

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

/**
 * @author zhunter
 * @create 2021-12-31-14:29
 *
 * Provide data for testing
 */
public class EmployeeData {

    public static List<Employee> getEmployees(){
        List<Employee> list = new ArrayList<>();

        list.add(new Employee(1001, "pony ", 34, 6000.38));
        list.add(new Employee(1002, "Jack Ma", 12, 9876.12));
        list.add(new Employee(1003, "Qiang Dong Liu", 33, 3000.82));
        list.add(new Employee(1004, "Lei Jun", 26, 7657.37));
        list.add(new Employee(1005, "Robin Li", 65, 5555.32));
        list.add(new Employee(1006, "Bill Gates", 42, 9500.43));
        list.add(new Employee(1007, "Ren Zhengfei", 26, 4333.32));
        list.add(new Employee(1008, "Mark Zuckerberg ", 35, 2500.32));

        return list;
    }
}

Employee class

package week4.day28;

/**
 * @author zhunter
 * @create 2021-12-31-13:33
 */

public class Employee {

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

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public double getSalary() {
        return salary;
    }

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

    public Employee() {
        System.out.println("Employee().....");
    }

    public Employee(int id) {
        this.id = id;
        System.out.println("Employee(int id).....");
    }

    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public Employee(int id, String name, int age, double salary) {

        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee{" + "id=" + id + ", 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;

        Employee employee = (Employee) o;

        if (id != employee.id)
            return false;
        if (age != employee.age)
            return false;
        if (Double.compare(employee.salary, salary) != 0)
            return false;
        return name != null ? name.equals(employee.name) : employee.name == null;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = id;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + age;
        temp = Double.doubleToLongBits(salary);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
}


package week4.day28;

import org.junit.Test;

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

/**
 * @author zhunter
 * @create 2021-12-31-14:26
 *
 * 1.Stream Focus on the operation of data and dealing with CPU
 *   Collections focus on the storage of data and deal with memory
 *
 * 2.
 * ①Stream You don't store elements yourself.
 * ②Stream The source object will not be changed. Instead, they return a new Stream that holds the result.
 * ③Stream The operation is delayed. This means they wait until they need results
 *
 * 3.Stream Execution process
 * ① Stream Instantiation of
 * ② A series of intermediate operations (filtering, mapping,...)
 * ③ Terminate operation
 *
 * 4.explain:
 * 4.1 An intermediate operation chain that processes the data of the data source
 * 4.2 Once the termination operation is performed, the intermediate operation chain is executed and the results are generated. After that, it will not be used again
 */
public class StreamAPITest {
    //Method 1 of creating Stream: through collection
    @Test
    public void test1() {
        List<Employee> employees = EmployeeData.getEmployees();

        //Default stream < E > stream(): returns a sequential stream
        Stream<Employee> stream = employees.stream();

        //Default stream < E > parallelstream(): returns a parallel stream
        Stream<Employee> parallelStream = employees.parallelStream();
    }

    //Method 2 of creating Stream: through array
    @Test
    public void test2() {
        int[] arr = new int[]{1,2,3,4,5};
        //Call static < T > stream < T > stream (t [] array) of Arrays class: return a stream
        IntStream stream = Arrays.stream(arr);

        Employee e1 = new Employee(1001,"zzy");
        Employee e2 = new Employee(1001,"zzy");
        Employee[] employees = new Employee[]{e1,e2};
        Stream<Employee> stream1 = Arrays.stream(employees);
    }

    //Method 3 of creating a Stream: through of()
    @Test
    public void test3() {
        Stream<Integer> stream = Stream.of(1,2,3,4,5);
    }

    //Create Stream mode 4: create infinite Stream
    @Test
    public void test4() {
        //iteration
        //public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
        //Traverse the first 10 even numbers
        Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println);

        //generate
        //public static<T> Stream<T> generate(Supplier<T> s)
        Stream.generate(Math::random).limit(10).forEach(System.out::println);
    }
}

7.3 intermediate operation of stream: screening and slicing

Multiple intermediate operations can be connected to form a pipeline. Unless the termination operation is triggered on the pipeline, the intermediate operation will not perform any processing! When the operation is terminated, it is processed all at once, which is called "lazy evaluation".

methoddescribe
filter(Predicate p)Receive Lambda and exclude some elements from the stream
distinct()Filter to remove duplicate elements through hashCode() and equals() of the elements generated by the flow
limit(long maxSize)Truncate the stream so that its elements do not exceed the given number
skip(long n)Skip elements and return a stream that throws away the first n elements. If flow
package week4.day28;

import org.junit.Test;

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

/**
 * @author zhunter
 * @create 2021-12-31-14:46
 *
 * Intermediate operation of test Stream
 */
public class StreamAPITest1 {
    //1 - screening and slicing
    @Test
    public void test1() {
        List<Employee> list = EmployeeData.getEmployees();
        //Filter (predict P) -- receives Lambda and discharges some elements from the stream
        Stream<Employee> stream = list.stream();
        //Query the information of employees whose salary is greater than 7000 in the employee table
        stream.filter(e->e.getSalary()>7000).forEach(System.out::println);

        System.out.println();
        //limit(n) -- truncate the flow, and the number of period elements does not exceed the given number
        list.stream().limit(3).forEach(System.out::println);

        System.out.println();
        //skip(n) -- skip elements and return a stream that throws away the first n elements. If there are less than n elements in the stream, an empty stream is returned. Complementary to limit(n)
        list.stream().skip(3).forEach(System.out::println);

        System.out.println();
        //distinct() -- filter and remove duplicate elements through hashCode () and equals () of the elements generated by the stream
        list.add(new Employee(1001,"zzy",20,10000));
        list.add(new Employee(1001,"zzy",20,10000));
        list.add(new Employee(1001,"zzy",20,10000));

        System.out.println(list);

        System.out.println();
        list.stream().distinct().forEach(System.out::println);
    }

    //mapping
    @Test
    public void test2() {
        //map(Function f) -- receive a function as a parameter to convert elements into other forms or extract information. The function will be applied to each element and mapped to a new element.
        List<String> list = Arrays.asList("aa","bb","cc");
        list.stream().map(str->str.toUpperCase()).forEach(System.out::println);

        //Get the name of an employee whose name length is greater than 3.
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<String> nameStream = employees.stream().map(Employee::getName);
        nameStream.filter(name->name.length()>3).forEach(System.out::println);

        Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::fromStringToStream);
        streamStream.forEach(s->{
            s.forEach(System.out::println);
        });

        System.out.println();
        //flatMap(Function f) -- receive a function as a parameter, replace each value in the stream with another stream, and then connect all streams into one stream.
        Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);
        characterStream.forEach(System.out::println);
    }

    //Converts a collection of multiple characters in a string into an instance of the corresponding Stream
    public static Stream<Character> fromStringToStream(String str) {
        ArrayList<Character> list = new ArrayList<>();
        for (Character c:str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }

    @Test
    public void test3() {
        ArrayList list1 = new ArrayList();
        list1.add(1);
        list1.add(2);

        ArrayList list2 = new ArrayList();
        list2.add(3);
        list2.add(4);

//        list1.add(list2);
        list1.addAll(list2);
        System.out.println(list1);
    }

    //3-sort
    @Test
    public void test4() {
        //sorted() -- natural sort
        List<Integer> list = Arrays.asList(9,8,7,4,2,5,1,3);
        list.stream().sorted().forEach(System.out::println);
        //Throw exception. Reason: Employee does not implement Comparable interface
//        List<Employee> employees = EmployeeData.getEmployees();
//        employees.stream().sorted().forEach(System.out::println);

        //sorted(Comparable com) -- customized sorting
        List<Employee> employees = EmployeeData.getEmployees();
//        employees.stream().sorted((e1,e2)->Integer.compare(e1.getAge(),e2.getAge()))
//                .forEach(System.out::println);
        employees.stream().sorted((e1,e2)->{
            int ageValue = Integer.compare(e1.getAge(),e2.getAge());
            if (ageValue!=0) {
                return ageValue;
            } else {
                return Double.compare(e1.getSalary(),e2.getSalary());
            }
        })
                .forEach(System.out::println);
    }

}

7.4 intermediate operation of stream: mapping

package week4.day28;

import org.junit.Test;

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

/**
 * @author zhunter
 * @create 2021-12-31-14:46
 *
 * Intermediate operation of test Stream
 */
public class StreamAPITest1 {
    //1 - screening and slicing
    @Test
    public void test1() {
        List<Employee> list = EmployeeData.getEmployees();
        //Filter (predict P) -- receives Lambda and discharges some elements from the stream
        Stream<Employee> stream = list.stream();
        //Query the information of employees whose salary is greater than 7000 in the employee table
        stream.filter(e->e.getSalary()>7000).forEach(System.out::println);

        System.out.println();
        //limit(n) -- truncate the flow, and the number of period elements does not exceed the given number
        list.stream().limit(3).forEach(System.out::println);

        System.out.println();
        //skip(n) -- skip elements and return a stream that throws away the first n elements. If there are less than n elements in the stream, an empty stream is returned. Complementary to limit(n)
        list.stream().skip(3).forEach(System.out::println);

        System.out.println();
        //distinct() -- filter and remove duplicate elements through hashCode () and equals () of the elements generated by the stream
        list.add(new Employee(1001,"zzy",20,10000));
        list.add(new Employee(1001,"zzy",20,10000));
        list.add(new Employee(1001,"zzy",20,10000));

        System.out.println(list);

        System.out.println();
        list.stream().distinct().forEach(System.out::println);
    }

    //mapping
    @Test
    public void test2() {
        //map(Function f) -- receive a function as a parameter to convert elements into other forms or extract information. The function will be applied to each element and mapped to a new element.
        List<String> list = Arrays.asList("aa","bb","cc");
        list.stream().map(str->str.toUpperCase()).forEach(System.out::println);

        //Get the name of an employee whose name length is greater than 3.
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<String> nameStream = employees.stream().map(Employee::getName);
        nameStream.filter(name->name.length()>3).forEach(System.out::println);

        Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::fromStringToStream);
        streamStream.forEach(s->{
            s.forEach(System.out::println);
        });

        System.out.println();
        //flatMap(Function f) -- receive a function as a parameter, replace each value in the stream with another stream, and then connect all streams into one stream.
        Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);
        characterStream.forEach(System.out::println);
    }

    //Converts a collection of multiple characters in a string into an instance of the corresponding Stream
    public static Stream<Character> fromStringToStream(String str) {
        ArrayList<Character> list = new ArrayList<>();
        for (Character c:str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }

    @Test
    public void test3() {
        ArrayList list1 = new ArrayList();
        list1.add(1);
        list1.add(2);

        ArrayList list2 = new ArrayList();
        list2.add(3);
        list2.add(4);

//        list1.add(list2);
        list1.addAll(list2);
        System.out.println(list1);
    }

    //3-sort
    @Test
    public void test4() {
        //sorted() -- natural sort
        List<Integer> list = Arrays.asList(9,8,7,4,2,5,1,3);
        list.stream().sorted().forEach(System.out::println);
        //Throw exception. Reason: Employee does not implement Comparable interface
//        List<Employee> employees = EmployeeData.getEmployees();
//        employees.stream().sorted().forEach(System.out::println);

        //sorted(Comparable com) -- customized sorting
        List<Employee> employees = EmployeeData.getEmployees();
//        employees.stream().sorted((e1,e2)->Integer.compare(e1.getAge(),e2.getAge()))
//                .forEach(System.out::println);
        employees.stream().sorted((e1,e2)->{
            int ageValue = Integer.compare(e1.getAge(),e2.getAge());
            if (ageValue!=0) {
                return ageValue;
            } else {
                return Double.compare(e1.getSalary(),e2.getSalary());
            }
        })
                .forEach(System.out::println);
    }

}

7.5 intermediate operation of stream: sorting

package week4.day28;

import org.junit.Test;

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

/**
 * @author zhunter
 * @create 2021-12-31-14:46
 *
 * Intermediate operation of test Stream
 */
public class StreamAPITest1 {
    //1 - screening and slicing
    @Test
    public void test1() {
        List<Employee> list = EmployeeData.getEmployees();
        //Filter (predict P) -- receives Lambda and discharges some elements from the stream
        Stream<Employee> stream = list.stream();
        //Query the information of employees whose salary is greater than 7000 in the employee table
        stream.filter(e->e.getSalary()>7000).forEach(System.out::println);

        System.out.println();
        //limit(n) -- truncate the flow, and the number of period elements does not exceed the given number
        list.stream().limit(3).forEach(System.out::println);

        System.out.println();
        //skip(n) -- skip elements and return a stream that throws away the first n elements. If there are less than n elements in the stream, an empty stream is returned. Complementary to limit(n)
        list.stream().skip(3).forEach(System.out::println);

        System.out.println();
        //distinct() -- filter and remove duplicate elements through hashCode () and equals () of the elements generated by the stream
        list.add(new Employee(1001,"zzy",20,10000));
        list.add(new Employee(1001,"zzy",20,10000));
        list.add(new Employee(1001,"zzy",20,10000));

        System.out.println(list);

        System.out.println();
        list.stream().distinct().forEach(System.out::println);
    }

    //mapping
    @Test
    public void test2() {
        //map(Function f) -- receive a function as a parameter to convert elements into other forms or extract information. The function will be applied to each element and mapped to a new element.
        List<String> list = Arrays.asList("aa","bb","cc");
        list.stream().map(str->str.toUpperCase()).forEach(System.out::println);

        //Get the name of an employee whose name length is greater than 3.
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<String> nameStream = employees.stream().map(Employee::getName);
        nameStream.filter(name->name.length()>3).forEach(System.out::println);

        Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::fromStringToStream);
        streamStream.forEach(s->{
            s.forEach(System.out::println);
        });

        System.out.println();
        //flatMap(Function f) -- receive a function as a parameter, replace each value in the stream with another stream, and then connect all streams into one stream.
        Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);
        characterStream.forEach(System.out::println);
    }

    //Converts a collection of multiple characters in a string into an instance of the corresponding Stream
    public static Stream<Character> fromStringToStream(String str) {
        ArrayList<Character> list = new ArrayList<>();
        for (Character c:str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }

    @Test
    public void test3() {
        ArrayList list1 = new ArrayList();
        list1.add(1);
        list1.add(2);

        ArrayList list2 = new ArrayList();
        list2.add(3);
        list2.add(4);

//        list1.add(list2);
        list1.addAll(list2);
        System.out.println(list1);
    }

    //3-sort
    @Test
    public void test4() {
        //sorted() -- natural sort
        List<Integer> list = Arrays.asList(9,8,7,4,2,5,1,3);
        list.stream().sorted().forEach(System.out::println);
        //Throw exception. Reason: Employee does not implement Comparable interface
//        List<Employee> employees = EmployeeData.getEmployees();
//        employees.stream().sorted().forEach(System.out::println);

        //sorted(Comparable com) -- customized sorting
        List<Employee> employees = EmployeeData.getEmployees();
//        employees.stream().sorted((e1,e2)->Integer.compare(e1.getAge(),e2.getAge()))
//                .forEach(System.out::println);
        employees.stream().sorted((e1,e2)->{
            int ageValue = Integer.compare(e1.getAge(),e2.getAge());
            if (ageValue!=0) {
                return ageValue;
            } else {
                return Double.compare(e1.getSalary(),e2.getSalary());
            }
        })
                .forEach(System.out::println);
    }

}

7.6 termination of stream: matching and searching

The terminal operation generates results from the pipeline of the stream. The result can be any value that is not a stream, such as List, Integer, or even void.
The stream cannot be used again after it has been terminated.

package week4.day28;

import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author zhunter
 * @create 2021-12-31-15:31
 *
 * Test the termination of the Stream
 */
public class StreamAPITest2 {
    //1 - match and find
    @Test
    public void test1() {
        List<Employee> employees = EmployeeData.getEmployees();

//        allMatch(Predicate p) -- check whether all elements are matched.
//          Exercise: are all employees older than 18
        boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 23);
        System.out.println(allMatch);

//        anyMatch(Predicate p) -- check whether at least one element is matched.
//         Exercise: is there an employee whose salary is greater than 10000
        boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 9000);
        System.out.println(anyMatch);

//        Nonematch (predict P) -- check whether there are no matching elements.
//          Exercise: is there an employee surname "Ma"
        boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("horse"));
        System.out.println(noneMatch);

//        findFirst -- returns the first element
        Optional<Employee> employee = employees.stream().findFirst();
        System.out.println(employee);

//        findAny -- returns any element in the current stream
        Optional<Employee> employee1 = employees.parallelStream().findAny();
        System.out.println(employee1);
    }

    @Test
    public void test2() {
        List<Employee> employees = EmployeeData.getEmployees();

        // count -- returns the total number of elements in the stream
        long count = employees.stream().filter(e -> e.getSalary() > 4500).count();
        System.out.println(count);

//        max(Comparator c) -- returns the maximum value in the stream
//        Exercise: return to the highest salary:
        Stream<Double> salaryStream = employees.stream().map(e -> e.getSalary());
        Optional<Double> maxSalary = salaryStream.max(Double::compare);
        System.out.println(maxSalary);

//        min(Comparator c) -- the minimum value in the return stream
//        Exercise: return to the minimum wage employee
        Optional<Employee> employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(employee);
        System.out.println();

//        forEach(Consumer c) -- internal iteration
        employees.stream().forEach(System.out::println);

        //Traversal using a collection
        employees.forEach(System.out::println);
    }

    //2-reduction
    @Test
    public void test3() {
//        Reduce (T identity, binary operator) -- you can combine the elements in the stream repeatedly to get a value. Return T
//        Exercise 1: calculate the sum of natural numbers
        List<Integer> list = Arrays.asList(71,25,32,34,43,56,81,15,29,71);
        Integer sum = list.stream().reduce(0, Integer::sum);
        System.out.println(sum);

//        Reduce (binary operator) -- you can combine the elements in the stream repeatedly to get a value. Return to optional < T >
//        Exercise 2: calculate the total salary of all employees in the company
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
//        Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
        Optional<Double> sumMoney = salaryStream.reduce((d1,d2) -> d1 + d2);
        System.out.println(sumMoney.get());
    }

    //3 - Collection
    @Test
    public void test4() {
//        collect(Collector c) -- convert the Stream to other forms. Receive the implementation of a collector interface, which is used to summarize the elements in the Stream
//        Exercise 1: find employees whose salary is greater than 6000, and the result is returned as a List or Set

        List<Employee> employees = EmployeeData.getEmployees();
        List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());

        employeeList.forEach(System.out::println);

        System.out.println("******************************");

        Set<Employee> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());

        employeeSet.forEach(System.out::println);
    }
}

7.7 termination of stream: reduction

package week4.day28;

import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author zhunter
 * @create 2021-12-31-15:31
 *
 * Test the termination of the Stream
 */
public class StreamAPITest2 {
    //1 - match and find
    @Test
    public void test1() {
        List<Employee> employees = EmployeeData.getEmployees();

//        allMatch(Predicate p) -- check whether all elements are matched.
//          Exercise: are all employees older than 18
        boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 23);
        System.out.println(allMatch);

//        anyMatch(Predicate p) -- check whether at least one element is matched.
//         Exercise: is there an employee whose salary is greater than 10000
        boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 9000);
        System.out.println(anyMatch);

//        Nonematch (predict P) -- check whether there are no matching elements.
//          Exercise: is there an employee surname "Ma"
        boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("horse"));
        System.out.println(noneMatch);

//        findFirst -- returns the first element
        Optional<Employee> employee = employees.stream().findFirst();
        System.out.println(employee);

//        findAny -- returns any element in the current stream
        Optional<Employee> employee1 = employees.parallelStream().findAny();
        System.out.println(employee1);
    }

    @Test
    public void test2() {
        List<Employee> employees = EmployeeData.getEmployees();

        // count -- returns the total number of elements in the stream
        long count = employees.stream().filter(e -> e.getSalary() > 4500).count();
        System.out.println(count);

//        max(Comparator c) -- returns the maximum value in the stream
//        Exercise: return to the highest salary:
        Stream<Double> salaryStream = employees.stream().map(e -> e.getSalary());
        Optional<Double> maxSalary = salaryStream.max(Double::compare);
        System.out.println(maxSalary);

//        min(Comparator c) -- the minimum value in the return stream
//        Exercise: return to the minimum wage employee
        Optional<Employee> employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(employee);
        System.out.println();

//        forEach(Consumer c) -- internal iteration
        employees.stream().forEach(System.out::println);

        //Traversal using a collection
        employees.forEach(System.out::println);
    }

    //2-reduction
    @Test
    public void test3() {
//        Reduce (T identity, binary operator) -- you can combine the elements in the stream repeatedly to get a value. Return T
//        Exercise 1: calculate the sum of natural numbers
        List<Integer> list = Arrays.asList(71,25,32,34,43,56,81,15,29,71);
        Integer sum = list.stream().reduce(0, Integer::sum);
        System.out.println(sum);

//        Reduce (binary operator) -- you can combine the elements in the stream repeatedly to get a value. Return to optional < T >
//        Exercise 2: calculate the total salary of all employees in the company
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
//        Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
        Optional<Double> sumMoney = salaryStream.reduce((d1,d2) -> d1 + d2);
        System.out.println(sumMoney.get());
    }

    //3 - Collection
    @Test
    public void test4() {
//        collect(Collector c) -- convert the Stream to other forms. Receive the implementation of a collector interface, which is used to summarize the elements in the Stream
//        Exercise 1: find employees whose salary is greater than 6000, and the result is returned as a List or Set

        List<Employee> employees = EmployeeData.getEmployees();
        List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());

        employeeList.forEach(System.out::println);

        System.out.println("******************************");

        Set<Employee> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());

        employeeSet.forEach(System.out::println);
    }
}

The connection between map and reduce is usually called map reduce mode, which is famous for Google's use of it for web search.

7.8 termination of stream: Collection

package week4.day28;

import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author zhunter
 * @create 2021-12-31-15:31
 *
 * Test the termination of the Stream
 */
public class StreamAPITest2 {
    //1 - match and find
    @Test
    public void test1() {
        List<Employee> employees = EmployeeData.getEmployees();

//        allMatch(Predicate p) -- check whether all elements are matched.
//          Exercise: are all employees older than 18
        boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 23);
        System.out.println(allMatch);

//        anyMatch(Predicate p) -- check whether at least one element is matched.
//         Exercise: is there an employee whose salary is greater than 10000
        boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 9000);
        System.out.println(anyMatch);

//        Nonematch (predict P) -- check whether there are no matching elements.
//          Exercise: is there an employee surname "Ma"
        boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("horse"));
        System.out.println(noneMatch);

//        findFirst -- returns the first element
        Optional<Employee> employee = employees.stream().findFirst();
        System.out.println(employee);

//        findAny -- returns any element in the current stream
        Optional<Employee> employee1 = employees.parallelStream().findAny();
        System.out.println(employee1);
    }

    @Test
    public void test2() {
        List<Employee> employees = EmployeeData.getEmployees();

        // count -- returns the total number of elements in the stream
        long count = employees.stream().filter(e -> e.getSalary() > 4500).count();
        System.out.println(count);

//        max(Comparator c) -- returns the maximum value in the stream
//        Exercise: return to the highest salary:
        Stream<Double> salaryStream = employees.stream().map(e -> e.getSalary());
        Optional<Double> maxSalary = salaryStream.max(Double::compare);
        System.out.println(maxSalary);

//        min(Comparator c) -- the minimum value in the return stream
//        Exercise: return to the minimum wage employee
        Optional<Employee> employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(employee);
        System.out.println();

//        forEach(Consumer c) -- internal iteration
        employees.stream().forEach(System.out::println);

        //Traversal using a collection
        employees.forEach(System.out::println);
    }

    //2-reduction
    @Test
    public void test3() {
//        Reduce (T identity, binary operator) -- you can combine the elements in the stream repeatedly to get a value. Return T
//        Exercise 1: calculate the sum of natural numbers
        List<Integer> list = Arrays.asList(71,25,32,34,43,56,81,15,29,71);
        Integer sum = list.stream().reduce(0, Integer::sum);
        System.out.println(sum);

//        Reduce (binary operator) -- you can combine the elements in the stream repeatedly to get a value. Return to optional < T >
//        Exercise 2: calculate the total salary of all employees in the company
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
//        Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
        Optional<Double> sumMoney = salaryStream.reduce((d1,d2) -> d1 + d2);
        System.out.println(sumMoney.get());
    }

    //3 - Collection
    @Test
    public void test4() {
//        collect(Collector c) -- convert the Stream to other forms. Receive the implementation of a collector interface, which is used to summarize the elements in the Stream
//        Exercise 1: find employees whose salary is greater than 6000, and the result is returned as a List or Set

        List<Employee> employees = EmployeeData.getEmployees();
        List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());

        employeeList.forEach(System.out::println);

        System.out.println("******************************");

        Set<Employee> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());

        employeeSet.forEach(System.out::println);
    }
}

The implementation of the method in the Collector interface determines how to perform collection operations (such as collecting List, Set and Map).

Collectors utility class provides many static methods, which can easily create common collector instances. The specific methods and examples are as follows:

8. Optional class

8.1 introduction to optional class

By far, the notorious null pointer exception is the most common cause of failure in Java applications. Previously, in order to solve the null pointer exception, Google's famous guava project introduced the Optional class. Guava prevents code pollution by checking null values, which encourages programmers to write cleaner code. Inspired by Google Guava, the Optional class has become part of the Java 8 class library.

  • The optional class (java.util.Optional) is a container class that can store the value of type T, representing the existence of this value. Or just save null, indicating that the value does not exist. Originally, null was used to indicate that a value does not exist. Now optional can better express this concept. And you can avoid null pointer exceptions.
  • The Javadoc of the Optional class is described as follows: This is a null able container object. If the value exists, the isPresent() method will return true, and calling the get() method will return the object.
  • Optional provides many useful methods so that we don't need to explicitly detect null values.
  • Method to create an Optional class object:
    • Optional. Of (T): create an optional instance, t must be non empty;
    • Optional.empty(): create an empty optional instance
    • Optional. Ofnullable (T): t can be null
  • Determine whether the Optional container contains objects:
    • boolean isPresent(): judge whether objects are included
    • Void ifpresent (Consumer <? Super T > Consumer): if there is a value, the implementation code of the Consumer interface will be executed, and the value will be passed to it as a parameter.
  • Get the object of the Optional container:
    • T get(): if the calling object contains a value, return the value; otherwise, throw an exception
    • T orElse(T other): if there is a value, it will be returned; otherwise, the specified other object will be returned.
    • T orelseget (Supplier <? Extensions T > other): if there is a value, it will be returned; otherwise, it will return the object provided by the Supplier interface implementation.
    • T orelsethrow (Supplier <? Extensions x > exceptionsupplier): if there is a value, it will be returned; otherwise, an exception provided by the Supplier interface implementation will be thrown.
package week4.day28;

import org.junit.Test;

import java.util.Optional;

/**
 * @author zhunter
 * @create 2021-12-31-15:52
 *
 * Optional Class: created to avoid null pointer exceptions in programs.
 *
 * Common methods: ofnullable (T)
 *           orElse(T t)
 */
public class OptionalTest {
    /**
     * Optional.of(T t) : To create an Optional instance, t must be non empty;
     * Optional.empty() : Create an empty Optional instance
     * Optional.ofNullable(T t): t Can be null
     */
    @Test
    public void test(){
        Girl girl = new Girl();
//        girl = null;
        //Of (T): ensure that t is not empty
        Optional<Girl> optionalGirl = Optional.of(girl);
    }

    @Test
    public void test2(){
        Girl girl = new Girl();
        girl = null;
        //Ofnullable (T): t can be null
        Optional<Girl> optionalGirl = Optional.ofNullable(girl);
        System.out.println(optionalGirl);
        //orElse(T t1): if the T encapsulated in the Optional internal package before the order is not empty, the internal t is returned
        //If the inner t is empty, the parameter t1 in the orElse() method is returned
        Girl girl1 = optionalGirl.orElse(new Girl("Zhao Liying"));
        System.out.println(girl1);
    }

    @Test
    public void test3(){
        Boy boy = new Boy();
        boy = null;
        String girlName = getGirlName(boy);
        System.out.println(girlName);
    }

    private String getGirlName(Boy boy) {
        return boy.getGirl().getName();
    }

    //Optimized getGirlName():
    public String getGirlName1(Boy boy){
        if(boy != null){
            Girl girl = boy.getGirl();
            if(girl != null){
                return girl.getName();
            }
        }
        return null;
    }

    @Test
    public void test4(){
        Boy boy = new Boy();
        boy = null;
        String girlName = getGirlName1(boy);
        System.out.println(girlName);
    }

    //Use getGirlName() of the Optional class:
    public String getGirlName2(Boy boy){

        Optional<Boy> boyOptional = Optional.ofNullable(boy);
        //boy1 must not be empty at this time
        Boy boy1 = boyOptional.orElse(new Boy(new Girl("Delireba")));

        Girl girl = boy1.getGirl();

        Optional<Girl> girlOptional = Optional.ofNullable(girl);
        //girl1 must not be empty
        Girl girl1 = girlOptional.orElse(new Girl("Gulinaza"));

        return girl1.getName();
    }

    @Test
    public void test5(){
        Boy boy = null;
        boy = new Boy();
        boy = new Boy(new Girl("Yang Mi"));
        String girlName = getGirlName2(boy);
        System.out.println(girlName);
    }
}

class Boy {
    private Girl girl;

    public Boy() {
    }

    public Boy(Girl girl) {
        this.girl = girl;
    }

    public Girl getGirl() {
        return girl;
    }

    public void setGirl(Girl girl) {
        this.girl = girl;
    }

    @Override
    public String toString() {
        return "Boy{" +
                "girl=" + girl +
                '}';
    }
}

class Girl {
    private String name;

    public Girl() {
    }

    public Girl(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Girl{" +
                "name='" + name + '\'' +
                '}';
    }
}

8.2 use examples of optional class

package week4.day28;

import org.junit.Test;

import java.util.Optional;

/**
 * @author zhunter
 * @create 2021-12-31-15:52
 *
 * Optional Class: created to avoid null pointer exceptions in programs.
 *
 * Common methods: ofnullable (T)
 *           orElse(T t)
 */
public class OptionalTest {
    /**
     * Optional.of(T t) : To create an Optional instance, t must be non empty;
     * Optional.empty() : Create an empty Optional instance
     * Optional.ofNullable(T t): t Can be null
     */
    @Test
    public void test(){
        Girl girl = new Girl();
//        girl = null;
        //Of (T): ensure that t is not empty
        Optional<Girl> optionalGirl = Optional.of(girl);
    }

    @Test
    public void test2(){
        Girl girl = new Girl();
        girl = null;
        //Ofnullable (T): t can be null
        Optional<Girl> optionalGirl = Optional.ofNullable(girl);
        System.out.println(optionalGirl);
        //orElse(T t1): if the T encapsulated in the Optional internal package before the order is not empty, the internal t is returned
        //If the inner t is empty, the parameter t1 in the orElse() method is returned
        Girl girl1 = optionalGirl.orElse(new Girl("Zhao Liying"));
        System.out.println(girl1);
    }

    @Test
    public void test3(){
        Boy boy = new Boy();
        boy = null;
        String girlName = getGirlName(boy);
        System.out.println(girlName);
    }

    private String getGirlName(Boy boy) {
        return boy.getGirl().getName();
    }

    //Optimized getGirlName():
    public String getGirlName1(Boy boy){
        if(boy != null){
            Girl girl = boy.getGirl();
            if(girl != null){
                return girl.getName();
            }
        }
        return null;
    }

    @Test
    public void test4(){
        Boy boy = new Boy();
        boy = null;
        String girlName = getGirlName1(boy);
        System.out.println(girlName);
    }

    //Use getGirlName() of the Optional class:
    public String getGirlName2(Boy boy){

        Optional<Boy> boyOptional = Optional.ofNullable(boy);
        //boy1 must not be empty at this time
        Boy boy1 = boyOptional.orElse(new Boy(new Girl("Delireba")));

        Girl girl = boy1.getGirl();

        Optional<Girl> girlOptional = Optional.ofNullable(girl);
        //girl1 must not be empty
        Girl girl1 = girlOptional.orElse(new Girl("Gulinaza"));

        return girl1.getName();
    }

    @Test
    public void test5(){
        Boy boy = null;
        boy = new Boy();
        boy = new Boy(new Girl("Yang Mi"));
        String girlName = getGirlName2(boy);
        System.out.println(girlName);
    }
}

class Boy {
    private Girl girl;

    public Boy() {
    }

    public Boy(Girl girl) {
        this.girl = girl;
    }

    public Girl getGirl() {
        return girl;
    }

    public void setGirl(Girl girl) {
        this.girl = girl;
    }

    @Override
    public String toString() {
        return "Boy{" +
                "girl=" + girl +
                '}';
    }
}

class Girl {
    private String name;

    public Girl() {
    }

    public Girl(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Girl{" +
                "name='" + name + '\'' +
                '}';
    }
}

Topics: Java JavaEE