Other new features of Java8

Introduction to new Java8 features

  • faster
  • Less code (added new syntax:Lambda expressions)
  • powerfulStream API
  • Facilitate parallel
  • Minimize null pointer exceptions
  • The Nashorn engine allows JS applications to run on the JVM

Parallel and serial streams

  • Parallel flow: a flow that divides a piece of content into multiple data blocks and processes each block separately with different threads; Compared to serial streams,Parallel streams can greatly improve the efficiency of program execution
  • Java 8 has been optimized for parallelism, making it easy to manipulate data
  • The Stream API can be passed declarativelyThe parallel (), sequential ()Switching between parallel and serial streams

Lambda expression *

  • A new set of grammar rules
  • The essence of Lambda expressions: as instances of functional interfacesIn other words, there is no meaning without the interface
    • This interface can only have one abstract method (Functional interface), so there is no need to write the name of the method
    • An object that provides a concrete implementation class for an interface can be abbreviated as a Lambda expression

Why use Lambda expressions

A Lambda is an anonymous function, and we can think of a Lambda expression as a piece of passable code (passing code like data); Use it to write cleaner, more flexible code; As a more compact code style, Java has improved its expressive power

Use of Lambda expressions

  • For example :(o1, o2) -> Integer.compare(o1, o2);

  • Format:

    • -> : The Lambda operator or arrow operator
    • -> left: Lambda parameter list (parameter list of abstract methods in the interface)
    • -> Right: Lambda body (the method body of the overwritten abstract method)
  • Conditions of use

    1. The interface must be functional
    2. Objects represented by anonymous implementation classes can now use Lambda expressions

Instances (six formats)

package com.atguigu.java1;

import org.junit.Test;

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

/ * * *@author lv
 * @create2021-03-08 19:28 * * Use of Lambda expressions: * * 1. For example :(o1, o2) -> Integer.compare(o1, o2); * -> : The Lambda operator or arrow operator * -> Left: the Lambda parameter list (the parameter list of the abstract method in the interface) * -> Right: the Lambda body (which is the method body of the overwritten abstract method) * * 3. Use of Lambda expressions: (There are 6 cases) * Summary: * -> Left: The parameter types of the Lambda parameter list can be omitted (type inference), and the parentheses can be omitted when the parameter list has only one argument * -> Right: The Lambda body should be wrapped with a pair of {}; If the body of a Lambda has only one execution statement (including the return statement), you can omit the curly braces and return keyword */
public class LambdaTest1 {
    /** * Syntax format 1: no parameter, no return value */
    @Test
    public void test (a) {
// Create an object for the interface implementation class
        Runnable r1 = new Runnable() {
            @Override
            public void run(a) {
                System.out.println("Hey, Beijing."); }}; r1.run();// Oh, Beijing
        System.out.println("Rewrite the above code with a Lambda expression.");
// -> : the Lambda operator
        Runnable r2 = () -> System.out.println("Hey Beijing!");
        r2.run(); // Ah, Beijing
    }

    /** * Syntax format 2: Lambda requires a parameter, but does not return a value */
    @Test
    public void test2 (a) {
        Consumer<String> cons = new Consumer<String>() {
            @Override
            public void accept(String str) { System.out.println(str); }}; cons.accept("123"); / / 123

        Consumer<String> cons1 = (String str) -> {
            System.out.println(str);
        };
        cons1.accept("With?"); / / the same
    }
    /** * syntax format 3: Data types can be omitted because they can be inferred at compile time. This is called "type inference" ** /
    @Test
    public void test3 (a) {
        Consumer<String> cons = new Consumer<String>() {
            @Override
            public void accept(String str) { System.out.println(str); }}; cons.accept("123"); / / 123

        Consumer<String> cons1 = (str) -> {
            System.out.println(str);
        };
        cons1.accept("With?"); / / the same

// Other types of inference
        ArrayList<String> list = new ArrayList<>(); // Type inference - generic
        int[] arr = new int[] {1.2.3};
        int[] arr1 = {1.2.3}; // Type inference - type
    }

    If only one parameter is required, the parentheses of the parameter can also be omitted
    @Test
    public void test4 (a) {
        Consumer<String> cons1 = (str) -> {
            System.out.println(str);
        };
        cons1.accept("With?"); / / the same

        Consumer<String> cons2 = (str) -> {
            System.out.println(str);
        };
        cons2.accept("With?"); / / the same
    }
    /** * syntax format 5: Lambda if more than two arguments are required, multiple statements can be executed, and there can be a return value */
    @Test
    public void test5 (a) {
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                returno1.compareTo(o2); }};int compare1 = com1.compare(10.20);
        System.out.println(compare1); // -1

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

        int compare2 = com2.compare(111.21);
        System.out.println(compare2); / / 1

    }
    When the body of a Lambda has only one statement, return and curly braces can consider omitting */
    @Test
    public void test6 (a) {
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                returno1.compareTo(o2); }};int compare1 = com1.compare(10.20);
        System.out.println(compare1); // -1

        Comparator<Integer> com2 = (o1, o2) -> o1.compareTo(o2);
        int compare2 = com2.compare(88.104);
        System.out.println(compare2); // -1}}Copy the code

FunctionalInterface

An interface is called a functional interface if only one abstract method is declared

What is a functional interface

  • An interface with only one abstract method is called a functional interface
  • Objects of anonymous implementation classes of the interface can be created using Lambda expressions
  • You can verify that an interface is a FunctionalInterface by using the @functionalinterface annotation on it
  • Java8’s rich functional interfaces are defined under the java.util.function package
  • The equivalent ofAn instance of a functional interface is a Lambda expression

When to use functional interfaces

  • When the development needs to define a functional interface, first look up whether the FUNCTIONAL interface provided by the JDK meets the requirements, before deciding whether to redefine

Java has four core functional interfaces built in

Customer Consumer interface

  • Parameter type: T
  • Return type: void
  • Void accept(T T) void accept(T T)

Supplier Supplier interface

  • Parameter type: None
  • Return type: T
  • Purpose: Object of type T containing method: T get()

Function<T, R> A functional interface

  • Parameter type: T
  • Return type: R
  • Purpose: Apply an operation to an object of type T and return the result; The result is an object of type R; R apply(T T)

Predicate specifies the type interface

  • Parameter type: T
  • Return type: Boolean
  • Purpose: Determines whether an object of type T satisfies the constraint and returns a Boolean value; Boolean test(T T)

The instance

package com.atguigu.java1;

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.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/ * * *@author lv
 * @createJava built-in four core functional interfaces * * 1. <T> void accept() * 2. Supplier<T> T get() * 3. Function<T, R> R apply(T T) * 4. Predicate<T> Boolean test(T T) * */
public class LambdaTest2 {
    @Test
    public void test (a) {
        Consumer<String> con1 = (str) -> System.out.println(str);
        con1.accept("The difference between a lie and a promise:");
        Supplier<String> sup1 = () -> "One to hear and one to say.";
        String str = sup1.get();
        System.out.println(str);
        Function<String, Integer> f1 = (o1) -> Integer.parseInt(o1);
        int apply = (int) f1.apply("123");
        System.out.println(apply);
        Predicate<Integer> p1 = (n) -> n > 12;
        boolean test = p1.test(1);
        System.out.println(test);

    }
    @Test
    public void test1 (a) {
        happyTime(2000.new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("Consumption on earth:" + aDouble);
                // Human consumption: 2000.0}});// Use a Lambda expression
        happyTime(1000, (money) -> System.out.println("Consumption on earth:" + money));
        // Consumption per person: 1000.0
    }
    public void happyTime (double money, Consumer<Double> con) {
        con.accept(money);
    }

    @Test
    public void test2 (a) {
        List<String> list = Arrays.asList("Beijing"."Xiking"."Nanjing"."Tokyo"."Tianjin");
        List<String> strings = filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("Beijing"); }}); System.out.println(strings);// [Beijing, Xijing, Nanjing, Tokyo]

// Use a Lambda expression
        List<String> filterString = filterString(list, s -> s.contains("Beijing"));
        System.out.println(filterString); // [Beijing, Xijing, Nanjing, Tokyo]
    }
    public List<String> filterString (List<String> list, Predicate<String> pre) {
        ArrayList<String> fList = new ArrayList<>();
        for (String s : list) {
/ / Lambda calls
            if(pre.test(s)) { fList.add(s); }}returnfList; }}Copy the code

Method references and constructor references

Method References

  • When you want to pass an operation to a Lambda body that already has an implemented method, you can use a method reference

  • Method references can be thought of as deep expressions of Lambda expressions; In other words, a method reference is a Lambda expression, that is, an object of an anonymous implementation class of a functional interface that refers to a method by its name and can be considered a syntactic sugar for a Lambda expression

  • Requirement: The argument list and return value type of the abstract method implementing the interface must be the same as the argument 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 use cases:

    • Case one, object :: instance method name
    • Case 2, class :: static method name
    • Case three, class :: instance method name

Requirements for method reference usage

  • Requires that the parameter list and return value type of the abstract method in the interface be the same as the parameter list and return value type of the method referenced by the method! (For Case 1 and Case 2)

  • 2. When the first argument to a functional interface method is the caller that needs to reference the method, and the second argument is an argument (or no argument) that needs to reference the method: ClassName :: methodName (case 3)

The instance

package com.atguigu.java2;

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;

/** * Use method references ** 1. Use case: When the operation to be passed to a Lambda body already has a method implemented, use method references! * * 2. Method references, which are essentially Lambda expressions, serve as instances of functional interfaces. So a * method reference is also an instance of a functional interface. * * 3. Use format: class (or object) :: method name * * 4. * case 1 Object :: non-static method * case 2 category :: static method * * case 3 category :: non-static method // This method is not very able to think of, there is difficulty * * 5. Requirement for method reference use: Requires that the parameter list and return value type of the abstract method in the interface be the same as the parameter list and return value type of the method referenced by the method! * * Created by shkstart. */
public class MethodRefTest {

	// Case 1: object :: instance method
	// Void accept(T T) in Consumer
	// void println(T T)
	@Test
	public void test1(a) {
		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");
	}
	@Test
	public void test11 (a) {
		Consumer<String> cons = str -> System.out.println(str);
		cons.accept("The bottom 1234567");
		PrintStream ps = System.out;
		Consumer<String> cons1 = ps :: print;
		cons1.accept("Come on boy");
	}
	
	//Supplier T get()
	//Employee String getName()
	@Test
	public void test2(a) {
		Employee emp = new Employee(1001."Tom".23.5600);

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

		System.out.println("* * * * * * * * * * * * * * * * * * *");
		Supplier<String> sup2 = emp::getName;
		System.out.println(sup2.get());

	}
	@Test
	public void test22 (a) {
		Employee emp = new Employee(1002."Tommer".15.8520);
		Supplier<String> sp = () -> emp.getName();
		String string = sp.get();
		System.out.println(string);
		Supplier<String> sp1 = emp :: getName;
		String s = sp1.get();
		System.out.println(s);

	}

	// Case 2: class :: static method
	Int compare(T t1,T t2) int compare(T t1,T t2)
	Int compare(T t1,T t2)
	@Test
	public void test3(a) {
		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(12.3));

	}
	@Test
	public void test33 (a) {
		Comparator<Integer> com = (o1, o2) -> Integer.compare(o1, o2);
		System.out.println(com.compare(123.456)); // -1
		Comparator<Integer> com1 = Integer :: compare;
		System.out.println(com1.compare(111.123)); // -1
		/** * graft: same return value type, parameter list type */

	}
	
	//Function R apply(T T)
	// Long round(Double d)
	@Test
	public void test4(a) {
		Function<Double,Long> func = new Function<Double, Long>() {
			@Override
			public Long apply(Double d) {
				returnMath.round(d); }}; 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.6));
	}
	@Test
	public void test44 (a) {
		Function<Double, Long> f1 = d -> Math.round(d);
		Long aLong = f1.apply(2.4);
		System.out.println(aLong); / / 2
		Function<Double, Long> f11 = Math ::round;
		Long aLong1 = f11.apply(12.5);
		System.out.println(aLong1); / / 13
	}

	// Case 3: class :: instance method (difficult)
	Int comapre(T t1,T t2)
	Int t1.compareTo(t2) pareTo(t2)
	@Test
	public void test5(a) {
		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("abd"."abm"));
	}
	@Test
	public void test55 (a) {
		Comparator<String> com = (s1, s2) -> s1.compareTo(s2);
		int compare = com.compare("abc"."abd");
		System.out.println(compare); // -1
		Comparator<String> com1 = String ::compareTo;
		int compare1 = com1.compare("ac"."ad");
		System.out.println(compare1); // -1
	}

	Boolean test(T t1, T t2); // Predicate Boolean test(T t1, T t2);
	//String in Boolean t1.equals(t2)
	@Test
	public void test6(a) {
		BiPredicate<String,String> pre1 = (s1,s2) -> s1.equals(s2);
		System.out.println(pre1.test("abc"."abc"));

		System.out.println("* * * * * * * * * * * * * * * * * * *");
		BiPredicate<String,String> pre2 = String :: equals;
		System.out.println(pre2.test("abc"."abd"));
	}
	@Test
	public void test66 (a) {
// BiPredicate
      
        bp = (s1, s2) -> s1.equals(s2);
      ,>
		BiPredicate<String, String> bp = (s1, s2) -> s1.contains(s2);
		boolean test = bp.test("123"."2");
		System.out.println(test); // true
		BiPredicate<String, String> bp1 = String :: equals;
		boolean test1 = bp1.test("ab"."ad");
		System.out.println(test1); // false

	}
	
	// Function R apply(T T)
	// Employee String getName();
	@Test
	public void test7(a) {
		Employee employee = new Employee(1001."Jerry".23.6000);


		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));


	}
	@Test
	public void test77 (a) {
		Employee e1 = new Employee(1022."Jerry".22.963);
		Function<String, Integer> f1 = s -> Integer.parseInt(s);
		Integer apply = f1.apply("123");
		System.out.println(apply); // 123Function<String, Integer> f1 = s -> Integer.parseInt(s);

		Function<Employee, String> f11 = s -> s.getName();
		String apply11 = f11.apply(e1);
		System.out.println(apply11); // Jerry
		Function<Employee, String> f2 = Employee :: getName;
		String apply1 = f2.apply(e1);
		System.out.println(apply1); // Jerry}}Copy the code

Constructor reference

  • Format: Class name :: new
  • Similar to method references, the parameter list of the abstract method of a functional interface is the same as the parameter list of the constructor

The instance

package com.atguigu.java2;

import org.junit.Test;

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

Constructor references * Like method references, the parameter list of the abstract method of a functional interface is the same as the parameter list of the constructor. The return value of an abstract method is the type of the class to which the constructor belongs * * Array reference * We can think of an array as a special class, so we write the same as the constructor reference. * * Created by shkstart */
public class ConstructorRefTest {
	// Constructor reference
    //Supplier T get()
    //Employee null constructor: Employee()
    @Test
    public void test1(a){

        Supplier<Employee> sup = new Supplier<Employee>() {
            @Override
            public Employee get(a) {
                return newEmployee(); }}; 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());
    }
    @Test
    public void test11 (a) {
        Supplier<Employee> sup = () -> new Employee();
        Employee emp1 = sup.get();
        System.out.println(emp1);

// Constructor reference
        Supplier<Employee> sup2 = Employee :: new;
        Employee emp2 = sup2.get();
        System.out.println(emp2);

    }

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

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

        Function<Integer,Employee> func2 = Employee :: new;
        Employee employee1 = func2.apply(1002);
        System.out.println(employee1);

    }
    @Test
    public void test22 (a) {
        Function<Integer, Employee> f = id -> new Employee(id);
        Employee emp1 = f.apply(123);
        System.out.println(emp1);

        Function<Integer, Employee> f1 = Employee ::new;
        Employee emp2 = f1.apply(456);
        System.out.println(emp2);

    }

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

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

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

    }
    @Test
    public void test33 (a) {
        BiFunction<Integer, String, Employee> f1 = (id, name) -> new Employee(id, name);
        Employee tom = f1.apply(789."Tom");
        System.out.println(tom);
        BiFunction<Integer, String, Employee> f2 = Employee :: new;
        Employee jerry = f2.apply(741."Jerry");
        System.out.println(jerry);
    }

	// Array reference
    //Function R apply(T T)
    @Test
    public void test4(a){
        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 = func2.apply(10);
        System.out.println(Arrays.toString(arr2));

    }
    @Test
    public void test44 (a) {
        Function<Integer, Integer[]> f1 = i -> new Integer[i];
        Integer[] arrInt = f1.apply(3);
        System.out.println(arrInt.length); / / 3
        System.out.println(Arrays.toString(arrInt)); // [null, null, null]

        Function<Integer, String[]> f2 = String[] :: new;
        String[] arrStr = f2.apply(5);
        System.out.println(arrStr.length); / / 5
        System.out.println(Arrays.toString(arrStr)); // [null, null, null, null, null]}}Copy the code

An array reference

  • Format: Array type [] :: new
  • We can think of the array as a special class, which is written in the same way as the constructor reference

The instance


    // Array reference
    //Function R apply(T T)
    @Test
    public void test4(a){
        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 = func2.apply(10);
        System.out.println(Arrays.toString(arr2));

    }
    @Test
    public void test44 (a) {
        Function<Integer, Integer[]> f1 = i -> new Integer[i];
        Integer[] arrInt = f1.apply(3);
        System.out.println(arrInt.length); / / 3
        System.out.println(Arrays.toString(arrInt)); // [null, null, null]

        Function<Integer, String[]> f2 = String[] :: new;
        String[] arrStr = f2.apply(5);
        System.out.println(arrStr.length); / / 5
        System.out.println(Arrays.toString(arrStr)); // [null, null, null, null, null]

    }
Copy the code

Powerful Stream API *

Reasons to use the Stream API

A Collection is a static in-memory data structure, while a Stream is computational; The former is mainly memory oriented, where data is stored, while the latter is mainly CPU oriented, through which computing is implemented

What is the Stream

Is a data channel for manipulating sequences of elements produced by data sources (collections, arrays, etc.); Set is about data, Stream is about computation

Note:

  • Stream itself does not store elements (similar to iterators)
  • Stream does not change the source object; Instead, they return a new Stream that holds the result
  • Stream operations are delayed; This means that they wait until the results are needed

Three steps of Stream operation

  1. Create a Stream

A data source (e.g., collection, array) that gets a stream

  1. In the middle of operation

An intermediate chain of operations that processes data from a data source

  1. Terminate operation (terminal operation)

Once the termination operation is performed, the chain of intermediate operations is executed and results are produced; After that, it will not be used again

How to create a Stream (instantiate)

Method 1: Through the collection

The Collection interface in Java8 has been extended to provide two methods for fetching streams:

  • Default Stream Stream () : Returns a sequential Stream
  • Default Stream parallelStream() : returns a parallelStream
// Create a Stream using a collection
    @Test
    public void test(a) {
        List<Employee> employees = EmployeeData.getEmployees();
// default Stream
      
        Stream () : returns a sequential Stream
      
        Stream<Employee> stream = employees.stream();

// default Stream
      
        parallelStream() : return a parallelStream
      
        Stream<Employee> parallelStream = employees.parallelStream();

    }
Copy the code

Method two: Through an array

The static stream() method of Arrays in Java8 retrieves an array stream:

  • Static Stream Stream (T[] array) : returns a Stream

Overloaded form that can handle arrays of the corresponding basic types:

  • public static IntStream stream(int[] array)
  • public static LongStream stream(long[] array)
  • public static DoubleStream stream(double[] array)

    /** * The array is */
    @Test
    public void test1 (a) {
        int[] ints = {1.2.3.4.5.6};
Static 
      
        Stream
       
         Stream (T[] array) : returns a Stream
       
        IntStream stream = Arrays.stream(ints);
        Employee e1 = new Employee(1001."Tom");
        Employee e2 = new Employee(1002."Jerry");
        Employee[] arrEmps = new Employee[]{e1, e2};
        Stream<Employee> employeeStream = Arrays.stream(arrEmps);
    }
Copy the code

Method 3: Through Stream of()

You can create a Stream by displaying values by calling the static method of() of the Stream class. It can accept any number of arguments

  • public static Stream of(T… Values) : returns a stream
    /** ** ** ** ** **
    @Test
    public void test2 (a) {
        Stream<Integer> integerStream = Stream.of(1.2.3);
    }
Copy the code

Method 4: Create an infinite stream

You can use the static methods stream.iterate () and stream.generate () to create an infinite Stream

  • Iterate: public static Stream iterate(final T seed, final UnaryOperator f)
  • Public static Stream generate(Supplier s)

    /** * Method 4: Create an infinite stream */
    @Test
    public void test3 (a) {
// iterate: public static
      
        Stream
       
         iterate(final T seed, final UnaryOperator
        
          f)
        
        Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out :: println);

Public static
      
        Stream
       
         generate(Supplier
        
          s)
        
        Stream.generate(Math ::random).limit(10).forEach(System.out :: println);

    }
Copy the code

Intermediate operations for Stream

Multiple intermediate operations can be connected to form a pipeline, and the intermediate operations do not perform any processing unless a termination is triggered on the pipeline! When the operation is terminated, it is processed all at once, known as lazy evaluation

1. Screening and slicing

  • Filter (Predicate P) : Receives a Lambda, excluding certain elements from the stream
  • Distinct () : filter that removes duplicate elements through hashCode() and equals() of the elements generated by the stream
  • Limit (long maxSize) : Truncates the stream so that it does not exceed a given number of elements
  • 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. And limit (n) complement each other
package com.atguigu.java3;

import com.atguigu.java2.Employee;
import com.atguigu.java2.EmployeeData;
import org.junit.Test;

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

/ * * *@author lv
 * @createThe 2021-03-14 * / seated
public class StreamAPITest1 {
    @Test
    public void test (a) {
        List<Employee> employeeList = EmployeeData.getEmployees();

        Stream<Employee> stream = employeeList.stream();
// 1.filter(Predicate p) : accepts Lambda, excluding certain elements from the stream
// stream.filter(e -> e.getSalary() > 7000);
Select * from employee where salary > 7000
        stream.filter(e -> e.getSalary() > 7000).forEach(System.out :: println);

// 2. Limit (long maxSize) : truncates the stream so that it does not exceed a given number of elements
// stream.limit(5).forEach(System.out :: println);
// Error: IllegalStateException: stream has already been operated upon or closed
        System.out.println();
        employeeList.stream().limit(5).forEach(System.out :: println);

        /** * 3. Skip (long n) : return a stream that drops the first n elements; If there are less than n elements in the stream, return an empty stream; Complementary to limit(n) */
        employeeList.stream().skip(5).forEach(e -> System.out.println(e.getName()));
        /** * Bill Gates * Ren Zhengfei * Zuckerberg */

        /** * 4. Distinct () : filter to remove duplicate elements */ through hashCode() and equals() of the generated elements of the stream
        employeeList.add(new Employee(1010."Ridker PM".40.8080));
        employeeList.add(new Employee(1010."Ridker PM".40.8080));
        employeeList.add(new Employee(1010."Ridker PM".40.8080));
        employeeList.add(new Employee(1010."Ridker PM".40.8080)); employeeList.stream().distinct().forEach(System.out :: println); }}Copy the code

2. The map

  • Map (Function f) : Takes a Function as an argument that is applied to each element and mapped to a new element
  • MapToDouble (ToDoubleFunction f) : Takes a function as an argument that is applied to each element, producing a new DoubleStream
  • MapToInt (ToIntFunction f) : takes a function as an argument that is applied to each element, producing a new IntStream
  • MapToLong (ToLongFunction f) : takes a function as an argument that is applied to each element, producing a new LongStream
  • FlatMap (Function f) : Takes a Function as a parameter, replaces each value in the stream with another one, and then connects all the streams into one
@Test
    public void test1 (a) {
        List<String> strList = Arrays.asList("aa"."bb"."dd"."ee");
        /** * map(Function f) : takes a Function as an argument, * this Function is applied to each element, and maps it to a new element */
        strList.stream().map(str -> str.toUpperCase()).forEach(System.out :: println);
        /** * AA * BB * DD * EE */
// Exercise 1: Get the name of an employee whose name length is longer than 3
        List<Employee> employeeList = EmployeeData.getEmployees();
// employeeList.stream().map(e -> e.getName()).filter(e -> e.length() > 3).forEach(System.out :: println);
// employeeList.stream().map(Employee :: getName ).filter(e -> e.length() > 3).forEach(System.out :: println);
        Stream<String> namesStream = employeeList.stream().map(Employee::getName);
        namesStream.filter(n -> n.length() > 3).forEach(System.out :: println);

        /** * Bill Gates * Zuckerberg */
        System.out.println();
// Exercise 2:
        Stream<Stream<Character>> streamStream = strList.stream().map(StreamAPITest1 :: fromStringToStream);
        streamStream.forEach(s -> {
// System.out.println("*");
            s.forEach(System.out :: println);
        });
        /** * a * a * b * b * d * d * e * e */
        /** * flatMap(Function f) : take a Function as an argument, * replace each value in the stream with another stream, and then connect all streams into one stream */
        System.out.println();
        Stream<Character> characterStream = strList.stream().flatMap(StreamAPITest1::fromStringToStream);
        characterStream.forEach(System.out :: println);
        /** * a * a * b * b * d * d * e * e */
    }

// Convert a collection of characters from a string to an instance of the Stream
    public static Stream<Character> fromStringToStream (String str) {
        ArrayList<Character> charList = new ArrayList<>();
        for(Character c : str.toCharArray()) {
            charList.add(c);
        }
        return charList.stream();
    }
    @Test
    public void test2 (a) {

        ArrayList list1 = new ArrayList();
        list1.add(1);
        list1.add(2);
        list1.add(3);
        ArrayList list2 = new ArrayList();
        list2.add(4);
        list2.add(5);
        list2.add(6);

// list1.add(list2);
// System.out.println(list1); // [1, 2, 3, [4, 5, 6]]
        list1.addAll(list2);
        System.out.println(list1); // [1, 2, 3, 4, 5, 6]

    }
Copy the code

3. Sorting

  • Sorted () : Generates a new stream that is sorted in natural order
  • Sorted (Compatator com) : Produces a new stream which is sorted in Compatator order

/** * 3
    @Test
    public void test3 (a) {
        /** * sorted() : natural sorted */
        List<Integer> integerList = Arrays.asList(12.456.78.5.63.5.45);
        integerList.stream().sorted().forEach(System.out :: println);

        List<Employee> employeesList = EmployeeData.getEmployees();
// employeesList.stream().sorted().forEach(System.out :: println);
        / * * * error: com. Atguigu. Java2. The Employee always be cast to java.lang.Com parable * the Employee class does not implement the Comparable interface * /

        /** * sorted(Comparator com) : */
// employeesList.stream()
// .sorted((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()))
// .forEach(System.out :: println);

        employeesList.stream()
                .sorted((e1, e2) -> {
                    int compare = Integer.compare(e1.getAge(), e2.getAge());
                    if(compare ! =0) {
                        return compare;
                    } else {
                        return -Double.compare(e1.getSalary(), e2.getSalary());
                    }
                }).forEach(System.out :: println);
    }
Copy the code

Termination of Stream

  • Terminal operations generate results from the pipeline of the flow; The result can be any value that is not a stream, such as List, Integer, or even void
  • Once a stream has been terminated, it cannot be used again

1. Match and search

  • AllMatch (Predicate P) : Checks whether all elements are matched
  • AnyMatch (Predicate p) : Checks whether at least one element is matched
  • NoneMatch (Predicate P) : Checks whether all elements are not matched
  • FindFirst () : returns the first element
  • FindAny () : Returns any element in the current stream
  • Count () : Returns the total number of elements in the stream
  • Max (Comparator c) : Returns the maximum value in the stream
  • Min (Comparator c) : returns the minimum value in the stream
  • The forEach (Consumer) c:Internal iterationUsing the Collection interface requires the user to iterate, calledExternal iteration; Instead, the Stream API uses internal iterations – it does the iterations for you)
package com.atguigu.java3;

import com.atguigu.java2.Employee;
import com.atguigu.java2.EmployeeData;
import org.junit.Test;

import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

/ * * *@author lv
 * @createIn the 2021-03-14 very * /
public class StreamAPITest2 {

    /** * 1
    @Test
    public void test (a) {
        List<Employee> employeeList = EmployeeData.getEmployees();
        /** * allMatch(Predicate p) : checks whether all elements are matched ** exercise: whether all employees are older than 18 ** /
        boolean allMatch = employeeList.stream().allMatch(e -> e.getAge() > 18);
        System.out.println(allMatch); // false

        /** * anyMatch(Predicate p) : Checks whether at least one element */ is matched
        boolean anyMatch = employeeList.stream().anyMatch(e -> e.getSalary() > 10000);
        System.out.println(anyMatch); // false

        /** * noneMatch(Predicate P) : Checks whether all elements are not matched * Exercise: Does employee name exist: last name "Ray" */
        boolean noneMatch = employeeList.stream().noneMatch(e -> e.getName().startsWith("Ray"));
        System.out.println(noneMatch); // false

        /** * findFirst() : returns the first element ** /
        Optional<Employee> first = employeeList.stream().findFirst();
        System.out.println(first); // Optional[Employee{id= 1007, name=' Employee ', age=34, salary=6000.38}]

        /** * findAny() : returns any element */ in the current stream
// Optional
      
        any = employeeList.stream().findAny();
      
        Optional<Employee> any = employeeList.parallelStream().findAny();
        System.out.println(any); // Optional[Employee{id= 1007, name=' Employee ', age=34, salary=6000.38}]

        /** * count() : returns the total number of elements in the stream */
        long count = employeeList.stream().count();
        System.out.println(count); / / 8

        /** * Max (Comparator c) : returns the maximum value in the stream * returns the maximum salary */
        Optional<Employee> maxEmployee = employeeList.stream().max((e1, e2) -> {
            return Double.compare(e1.getSalary(), e2.getSalary());
        });
        Stream<Double> doubleStream = employeeList.stream().map(e -> e.getSalary());
        Optional<Double> max = doubleStream.max(Double :: compare);
        System.out.println(max); / / Optional [9876.12]
        System.out.println(maxEmployee); // Optional[Employee{id=1002, name=' Employee ', age=12, salary=9876.12}]

        /** * min(Comparator c) : returns the minimum value in the stream */
// Optional
      
        minEmployee = employeeList.stream().min((e1, e2) -> {
      
// return Double.compare(e1.getSalary(), e2.getSalary());
/ /});
        Optional<Employee> minEmployee = employeeList.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(minEmployee); // Optional[Employee{id=1008, name=' Employee ', age=35, salary= 500.32}]

        /** * forEach(Consumer c) : 'internal iteration' (' external iteration '); * Instead, the Stream API uses internal iterations - it does that for you) */
        employeeList.stream().forEach(System.out :: println);

// default void forEach(Consumer con) : a method in a collectionemployeeList.forEach(System.out :: println); }}Copy the code

2. Reduction

  • Reduce (T iden, BinaryOperator B) : Can repeatedly combine elements in the stream to obtain a value; Return T

  • Reduce (BinaryOperator B) : Can repeatedly combine elements in the stream to obtain a value; Returns the Optional

  • Note: The map and Reduce connection is often referred to as the Map-Reduce pattern and is famous for Google’s use of it for web searches

    /** * 2
    @Test
    public void test1 (a) {
        /** * reduce(T iden, BinaryOperator b) : * reduce(T iden, BinaryOperator b) : * Returns the T * /
        List<Integer> asList = Arrays.asList(1.2.3.4.5.6.7.8.9.10);
        Integer reduceSum = asList.stream().reduce(0, Integer::sum);
        System.out.println(reduceSum);

        /** * reduce(BinaryOperator b) : * Can combine elements in the stream repeatedly to obtain a value; Returns the Optional < T > * /
        List<Employee> employeeList = EmployeeData.getEmployees();
        Stream<Double> doubleStream = employeeList.stream().map(Employee::getSalary);
// Optional
      
        salarySum = doubleStream.reduce(Double::sum); or
      
        Optional<Double> salarySum = doubleStream.reduce((d1, d2) -> d1 + d2);
        System.out.println(salarySum);

    }
Copy the code

3. Collect

  • Collect (Collector C) : converts the stream to another form; Receives a practice of a Collector interface for summarizing the elements in the Stream

  • Description: The implementation of the methods in the Collector interface determines how to perform the collection operations on streams (e.g., collect to a List, Set, Map); In addition, the Collectors utility class provides a number of static methods to easily create common collector instances. The following table lists the methods and instances:

    1. ToList: Collects elements from the stream into a List
    2. ToSet: Collects elements from the stream into a Set
    3. ToCollection: Collects elements from the flow into a created collection
    4. Counting: Counting the number of elements in a stream
    5. SummingInt: Sum over the integer attributes of elements in the stream
    6. AveragingInt: Calculates the average value of the Integer attribute of an element in the stream
    7. SummarizingInt: Collects statistics for the Integer attribute in the stream; For example: average
    /** * 3
    @Test
    public void test2 (a) {
        /** * collect(Collector c) : convert the stream to another form; Receive an internship at a Collector interface for methods of summarizing elements in a Stream * exercise: find employees with salaries greater than 6000 and return a List or Set */
        List<Employee> employeeList = EmployeeData.getEmployees();
        List<Employee> collectEmployee = employeeList.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
// System.out.println(collectEmployee);
        collectEmployee.forEach(System.out :: println);
        /** * Employee{id=1002, name=' Ma ', age=34, salary=6000.38} * Employee{id=1002, name=' Ma ', age=12, Salary =9876.12} * Employee{id=1004, name=' Leijun ', age=26, salary=7657.37} * Employee{id=1006, name=' Bill Gates ', age=42, Salary = 9500.43} * /
        System.out.println();
        Set<Employee> collectSet = employeeList.stream().filter(e -> e.getSalary() > 8000).collect(Collectors.toSet());
// System.out.println(collectSet);
        collectSet.forEach(System.out :: println);
// for (Employee e : collectSet) {
// System.out.println(e);
/ /}

        /** ** * Employee{id=1002, name=' Ma ', age=12, salary=9876.12} ** Employee{id=1006, name=' Bill Gates ', age=42, Salary = 9500.43} * /
    }
Copy the code

Optional class

The Optional class (java.util.Optional) is a container class that holds the value of type T, indicating that the value exists. Or just null, which means the value does not exist. Null means that a value does not exist, but 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 container object that can be null; The isPresent() method returns true if the value isPresent, and a call to get() returns the object

  • Optional provides a number of useful methods so that we don’t have to explicitly do null detection

To create an Optional object:

  • Option. of(T T) : Creates an Optional instance. T must be non-empty
  • Option.empty () : Create an empty Optional instance
  • Optional. OfNullable (T T) : T can be null
package com.atguigu.java4;

import org.junit.Test;

import java.util.Optional;

/ * * *@author lv
 * @create2021-03-16 20:53 * /
public class OptionalTest {

    /** * > Create an Optional object: ** - option.of (T T) : create an Optional instance. T must be non-empty * - option.empty () : Create an empty Optional instance * - option.ofnullable (T T) : T can be null */
    @Test
    public void test (a) {
        Girl girl = new Girl();
// of(T T) : must ensure that T must be non-null
        Optional<Girl> girl1 = Optional.of(girl);
        System.out.println(girl1); // Optional[Girl{name='null'}]
        Optional<Object> empty = Optional.empty();
        System.out.println(empty); // Optional.empty
        girl = null;
OfNullable (T T) : T can be null
        Optional<Girl> girl2 = Optional.ofNullable(girl);
        System.out.println(girl2); // Optional.empty}}Copy the code

Check whether the Optional container contains an object:

  • Boolean isPresent() : Determines whether an object is included
  • void ifPresent(Consumer
    ) : If there is a value, the implementation code for the Consumer interface is executed and the value is passed to it as an argument

Gets the Optional container object

  • T get() : Return a value if the calling object contains it, otherwise throw an exception
  • T orElse(T other) : returns a value if any, otherwise returns the specified other object
  • T orElseGet(Supplier
    other) : Returns a value if there is one, otherwise returns an object provided by the Supplier interface implementation
  • T orElseThrow(Supplier
    exceptionSupplier) : Returns a value if any, otherwise throws an exception provided by the Supplier interface implementation
package com.atguigu.java4;

import org.junit.Test;

import java.util.Optional;

/ * * *@author lv
 * @create2021-03-16 20:53 * * Optional: ofNullable(T T), orElse(T T) * */
public class OptionalTest {

    /** * > Create an Optional object: ** - option.of (T T) : create an Optional instance. T must be non-empty * - option.empty () : Create an empty Optional instance * - option.ofnullable (T T) : T can be null */
    @Test
    public void test (a) {
        Girl girl = new Girl();
// of(T T) : must ensure that T must be non-null
        Optional<Girl> girl1 = Optional.of(girl);
        System.out.println(girl1); // Optional[Girl{name='null'}]
        Optional<Object> empty = Optional.empty();
        System.out.println(empty); // Optional.empty
        girl = null;
OfNullable (T T) : T can be null
        Optional<Girl> girl2 = Optional.ofNullable(girl);
        /** * T orElse(T other) : returns a value if there is one, otherwise returns the specified other object */
        Girl girl3 = girl2.orElse(new Girl("Zhao Xiaoxiao"));
        System.out.println(girl2); // Optional.empty
        System.out.println(girl3); // Girl{name=' zhao Xiaoxiao '}
    }

    /** * example: Optional avoid null pointer exceptions */
    public String getGirlName (Boy boy) {
        return boy.getGirl().getName();
    }
// Optimized getGirlName()
    public String getGirlName1 (Boy boy) {
        if (null! = boy) { Girl girl = boy.getGirl();if (null! = girl)return girl.getName();
        }
        return null;
    }
// Use the Optional getGirlName2() class
    public String getGirlName2 (Boy boy) {
        Optional<Boy> optionalBoy = Optional.ofNullable(boy);
// Boy1 must not be empty
        Boy boy1 = optionalBoy.orElse(new Boy(new Girl("Xiao smile")));
        Girl girl = boy1.getGirl();
        Optional<Girl> optionalGirl = Optional.ofNullable(girl);
// Girl1 must not be empty
        Girl girl1 = optionalGirl.orElse(new Girl("Xiao Xiao Xiao"));
        return girl1.getName();
    }
    /** * example: Optional avoid null pointer exceptions */
    @Test
    public void test1 (a) {
        Boy boy = new Boy();
// String girlName = getGirlName(boy);
// System.out.println(girlName); // NullPointerException
        String girlName1 = getGirlName1(boy);
        System.out.println(girlName1); // null
        / / 1.
        String girlName2 = getGirlName2(boy);
        System.out.println(girlName2); / / xiao little smile
        / / 2.
        Boy boy1 = null;
        String girlName21 = getGirlName2(boy1);
        System.out.println(girlName21); / / xiao smiled
        / / 3.
        Boy boy2 = new Boy(new Girl("Lily"));
        String girlName22 = getGirlName2(boy2);
        System.out.println(girlName22); / / lily}}Copy the code

The problem

Static proxy: implements the Runnable interface method to create multithreading, that isStatic proxy mode

Class MyThread implements Runnable {} // The proxied class
Class Thread implements Runnable {} / / the proxy class
main () {
    MyThread t = new MyThread();
    Thread th = new Thread(T);
    th.start(); // Start the thread and call the thread's run()
}
Copy the code

Question:

  • The proxy class and the proxy class are determined at compile time, which is not good for program expansion
  • Each proxy class can only serve one set of interfaces, so there are too many proxy classes in the process of program development

A dynamic proxy

  • Proxy.newproxyinstance () dynamically creates a Proxy class
  • The InvocationHandler interface implements the class and its invoke() method to dynamically invoke the methods of the proxied class