Other new features of Java8
Introduction to new Java8 features
- faster
- Less code (added new syntax:
Lambda expressions
) - powerful
Stream 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 declaratively
The 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 interfaces
In 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
- This interface can only have one abstract method (
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
- The interface must be functional
- 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 of
An 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
- Create a Stream
A data source (e.g., collection, array) that gets a stream
- In the middle of operation
An intermediate chain of operations that processes data from a data source
- 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 iteration
Using 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:
- ToList: Collects elements from the stream into a List
- ToSet: Collects elements from the stream into a Set
- ToCollection: Collects elements from the flow into a created collection
- Counting: Counting the number of elements in a stream
- SummingInt: Sum over the integer attributes of elements in the stream
- AveragingInt: Calculates the average value of the Integer attribute of an element in the stream
- 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