New features of JDK 1.8 - Lambda expression, Stream API, functional interface, method reference

Keywords: Java Lambda JDK Database

jdk1.8 new feature knowledge points:
  • Lambda expression
  • Stream API
  • Functional interface
  • Method references and constructor calls
  • Default and static methods in the interface
  • New time date API
  • default
 
Lambda expression
Lambda is to simplify some of our previous complex codes, such as the judgment and comparison / sorting of collection content. We can traverse and judge to get the data we want or write an anonymous internal class compareto to get the data we want. In fact, they have made some judgment and comparison internally and finally returned to us result.
Example: scenario 1
Now we have three users, Xiaoming, Xiaohong and Xiaoqiang, whose ages are 16, 18 and 20 respectively. Now we want to rank these three users by age.
If it is written in the original way, the first thing we think about is to write an anonymous internal class Comparator for comparison, and then sort it to get the result we want
 
Example: scenario 2
Now we need to filter three users to get users older than 16. The first thing we want to think about is to traverse the set for judging and filtering, and finally put it into a new set, as shown in the figure:

 

Now JDK 1.8 provides us with a new way of Lambda expression, which is simpler and more brief than the code written in the above two examples. Let's see how it is simpler than the above code.

Scenario 1: attached drawings
Scenario 2: attached drawings

  

 
The following is the syntax summary of the Lmabda expression:
 
Pithy formula: left and right meet one parenthesis, left infers type Province
 
Note: when there are multiple abstract methods in an interface, if lambda expression is used, the corresponding abstract method cannot be matched intelligently, so the concept of functional interface is introduced.
 
First, I will introduce the Stream API. The Stream API is mentioned above. Next, I will introduce the functional interface.
Stream API:
Stream is a key abstract concept in Java 8 to deal with collections. It can specify the operations you want to perform on collections, and can perform very complex operations such as finding, filtering, and mapping data. Using Stream API to operate on collection data is similar to database query using SQL. You can also use the Stream API to perform operations in parallel. In short, the Stream API provides an efficient and easy-to-use way to process data.
Note: 1. Streams do not store elements themselves
2. Streams do not change the source objects, instead they return a Stream object that holds the new result set.
3.Stream operations are delayed, which means they wait until they need results
4. Only when the operation is regarded as termination, all intermediate operations will be executed at one time, which is called "lazy evaluation" and "delayed loading"
5. Each Stream can only be operated once. If the second operation will give an error, the stream has already been operated upon or closed
 
Execution process of Stream API:
Direct code:
1. Create Stream
2. Intermediate operation
3. Terminate operation
 1 //3.Terminate operation
 2 /**
 3 * Find and match
 4 * allMatch-Check to see if all elements match
 5 * anyMatch-Check to see if at least one element matches
 6 * noneMatch-Check if not all elements match
 7 * findFirst-Returns the first element
 8 * findAny-Returns any element in the current stream
 9 * count-Returns the total number of elements in the stream
10 * max-Returns the maximum value in the stream
11 * min-Minimum value in return flow
12 */
13 //3.1: allMatch Check whether all matching elements are valid and return true Otherwise return false
14 Stream<Map<String, Object>> stream2 = maps.stream();
15 boolean a = stream2.allMatch(x -> Integer.valueOf(x.get("age").toString()) > 16);
16 System.err.println("result:"+a); //false
17 //3.2: anyMatch Check whether at least one element is matched, and return as long as one element is established true
18 Stream<Map<String, Object>> stream3 = maps.stream();
19 boolean b = stream3.anyMatch(x -> Integer.valueOf(x.get("age").toString()) > 16);
20 System.err.println("result:"+b); //true
21 //3.3: noneMatch Check whether all elements are not matched. There are matching elements because they are valid. Estimation is not valid
22 Stream<Map<String, Object>> stream4 = maps.stream();
23 boolean c = stream4.noneMatch(x -> Integer.valueOf(x.get("age").toString()) > 16);
24 System.err.println("result:"+c); //false
25 //3.4:findFirst Returns the first element,Returns the first element in chronological order
26 Stream<Map<String, Object>> stream5 = maps.stream();
27 Map<String, Object> first = stream5.sorted((x,y) -> Integer.compare(Integer.valueOf(x.get("age")
28 .toString()),Integer.valueOf(y.get("age").toString()))).findFirst().get();
29 System.err.println(first.toString());//{sex=female, name=Small red, age=16}
30 //3.5: findAny-Returns any element in the current stream
31 Stream<Map<String, Object>> stream6 = maps.stream();
32 Map<String, Object> map = stream6.sorted((x,y) -> Integer.compare(Integer.valueOf(y.get("age")
33 .toString()),Integer.valueOf(x.get("age").toString()))).findAny().get();
34 //Multiple tests return a fixed value, which means there is an internal algorithm to sort and return a fixed value {sex=male, name=Xiao Ming, age=18}
35 //Always return the first after sorting
36 System.err.println(map.toString());
37 //3.6: Returns the total number of elements in the stream
38 Stream<Map<String, Object>> stream7 = maps.stream();
39 long count = stream7.count();
40 System.err.println("The length is:"+count); // Length: 3
41 //TODO The biggest and the smallest will not be tested. You can try it yourself

There are two more powerful termination operations, reduce and collect

Reduce operation: reduce:(T identity,BinaryOperator)/reduce(BinaryOperator) - you can repeatedly combine elements in the flow to get a value
 1 /**
 2 * reduce : Protocol operation
 3 * Calculation and
 4 * Calculate the result as x, then take the new value from the array as y, and carry out the next calculation
 5 * The result plus 0 is the final result
 6 */
 7 List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
 8 Integer count2 = list.stream().reduce(0, (x, y) -> x + y);
 9 System.out.println(count2);
10  
11 Stream<Map<String, Object>> stream8 = maps.stream();
12 //Calculating the total age can also be floating-point data Integer change into Double Just ok
13 Optional<Integer> op = stream8.map(m -> Integer.valueOf(String.valueOf(m.get("age"))))
14 .reduce(Integer::sum);
15 System.err.println(op.get()); //54    
Collect operation: collect - convert the Stream to other forms, receive the implementation of a Collection interface, which is used to summarize the elements in the Stream, and convert them to a new Collection or object
 1 /**
 2 * collect Action: Collect - converts the stream to another form,
 3 * Receive the implementation of a Collection interface to summarize the elements in the Stream
 4 * Collectors.toList()/toSet()
 5 */
 6 Set<Integer> ageList = list.stream().collect(Collectors.toSet());
 7 ageList.stream().forEach(System.out::println);
 8 //Take a name and seal it into hashset
 9 HashSet<Integer> hs = list.stream()
10 .collect(Collectors.toCollection(HashSet::new));
11 System.err.println(hs.toString());

Functional interface:

The functional interface is proposed to provide better support for the use of Lambda expressions.
What is a functional interface?
In short, it only defines the interface of an abstract method (except the public method of the Object class), which is a functional interface, and also provides an annotation: @ FunctionalInterface
Functional interface is an interface with and only one abstract method, but it can have multiple non abstract methods.
A functional interface can be implicitly converted to a lambda expression.
On Lambda expressions and method references (also considered Lambda expressions in fact).
For example, a functional interface is defined as follows:
1 @FunctionalInterfaceinterface GreetingService
2 {
3         void sayMessage(String message);
4 }
5  
6 // Then it can be used Lambda Expression to represent an implementation of the interface(Note: JAVA 8 Previously, it was generally implemented with anonymous classes): 
7 GreetingService greetService1 = message -> System.out.println("Hello " + message);
Four common functional interfaces are:
Consumer: consumer interface, with or without parameter return value
Supplier "T": supply type interface, no parameter return value
Function "T,R": function interface, with parameters and return values
Predicate: assertion type interface, with parameters and return values. T he return value is boolean type
 1 /**
 2 * @MethodName: functionInterface
 3 * @Description: Four functional interface exercises
 4 * @param
 5 * @return
 6 * @author rongrong
 7 * @date 2019-12-23
 8 */
 9 public void functionInterface(){
10 /**
11 * 1.Consumer <T>: Consumption interface, with or without parameter return value
12 * Print:
13 * 222222
14 * hello
15 */
16 changeStr("hello",(str) -> System.err.println(str));
17  
18 /**
19 * 2.Supplier <T>: Supply type interface, no parameter return value
20 * Print:
21 * 111111
22 * str
23 */
24 String value = getValue(() -> "str");
25 System.err.println(value);
26  
27 /**
28 * 3. Function <T,R>: :Function interface with parameter and return value
29 * Print:
30 * 333333
31 * 20000
32 */
33 Long aLong = changeNum(100L, x -> x * 200);
34 System.err.println(aLong);
35 /**
36 * Predicate<T>:  Assertion type interface, with parameters and return values. The return value is boolean type
37 * Print:
38 * true
39 */
40 boolean rongrong = changeBoolean("rongrong", x -> x.equals("rongrong"));
41 System.err.println(rongrong);
42  
43 }
44  
45 /**
46 * Consumer<T> Consumer interface
47 * @param str
48 * @param con
49 */
50 public void changeStr(String str, Consumer<String> con){
51 System.err.println("222222");
52 con.accept(str);
53 }
54  
55 /**
56 * Supplier<T> Supply type interface
57 * @param sup
58 * @return
59 */
60 public String getValue(Supplier<String> sup){
61 System.err.println("111111");
62 return sup.get();
63 }
64  
65 /**
66 * Function<T,R> Functional interface
67 * @param num
68 * @param fun
69 * @return
70 */
71 public Long changeNum(Long num, Function<Long, Long> fun){
72 System.err.println("333333");
73 return fun.apply(num);
74 }
75  
76 /**
77 * Predicate<T> Assertion interface
78 * @param str
79 * @param pre
80 * @return
81 */
82 public boolean changeBoolean(String str, Predicate<String> pre){
83 return pre.test(str);
84 }

On the basis of the four core functional interfaces, it also provides extended functional interfaces such as BiFunction, BinaryOperation, toIntFunction, etc., which are all extended from these four functional interfaces, so we will not elaborate.

Conclusion: the functional interface is proposed to make it more convenient for us to use lambda expressions. We don't need to create a functional interface by ourselves, just use it directly. The detailed interface description is below.
 
 
Method reference:
If the content in the body of a lambda has a method implemented, then you can use "method reference" to understand that method reference is another representation of a lambda expression and its syntax is simpler than a lambda expression
(a) Method reference
Three forms of expression:
1. Object: instance method name
2. Class:: static method name
3. Class:: instance method name (the first parameter in the lambda parameter list is the caller of the instance method, and the second parameter is available when it is the parameter of the instance method)
 1 /**
 2 *be careful:
 3 * 1.lambda The parameter list and return value type of the calling method in the body should be consistent with the function list and return value type of the abstract method in the functional interface!
 4 * 2.If the first parameter in the lambda parameter list is the caller of the instance method, and the second parameter is the parameter of the instance method, ClassName::method can be used
 5 * The example written at the bottom is not simplified at the top, but simplified at the bottom, which is method reference
 6 */
 7  
 8 //100
 9 //200
10 Consumer<Integer> con = (x) -> System.out.println(x);
11 con.accept(100);
12 // Method reference-object::Example method
13 Consumer<Integer> con2 = System.out::println;
14 con2.accept(200);
15  
16 // Method reference-Class name::Static method name
17 BiFunction<Integer, Integer, Integer> biFun = (x, y) -> Integer.compare(x, y);
18 Integer apply = biFun.apply(100, 200);
19 BiFunction<Integer, Integer, Integer> biFun2 = Integer::compare;
20 Integer result = biFun2.apply(100, 200);
21 //-1:-1
22 System.err.println(apply + ":" + result);
23  
24 // Method reference-Class name::Instance method name
25 BiFunction<String, String, Boolean> fun1 = (str1, str2) -> str1.equals(str2);
26 Boolean apply1 = fun1.apply("rong", "rong");
27 BiFunction<String, String, Boolean> fun2 = String::equals;
28 Boolean result2 = fun2.apply("hello", "world");
29 //true:false
30 System.out.println(apply1 + ":" + result2);
(b) Constructor reference
Format: ClassName::new
 1 // Constructor reference class name::new
 2 Supplier<String> sup = () -> new String();
 3 System.out.println(sup.get());
 4 Supplier<String> sup2 = String::new;
 5 System.out.println(sup2.get());
 6  
 7 // Constructor reference class name::new (With a parameter)
 8 //x The delegate is the parameter passed in, that is, the Integer type
 9 //new String(...) Represents the String type
10 Function<Integer, String> fun = x -> new String(String.valueOf(x));
11 System.err.println(fun.apply(100));
12 Function<String, String> fun3 = String::new;
13 System.out.println(fun3.apply("100"));
(c) Array reference
Format: type []: New
1 // Array reference
2 Function<Integer, String[]> arrayFun = (x) -> new String[x];
3 Function<Integer, String[]> arrayFun2 = String[]::new;
4 //to String The array has two lengths set. But the value is null
5 String[] strArray = arrayFun2.apply(2);
6 Arrays.stream(strArray).forEach(System.out::println);
 
Serial number
Interface & Description
1
BiConsumer<T,U>
Represents an operation that accepts two input parameters and does not return any results
2
BiFunction<T,U,R>
Represents a method that accepts two input parameters and returns a result
3
BinaryOperator<T>
Represents an operation that acts on two operators of the same type and returns results of the same type
4
BiPredicate<T,U>
Represents a boolean value method of two parameters
5
BooleanSupplier
Represents the provider of boolean value results
6
Consumer<T>
Represents an operation that accepts an input parameter and does not return
7
DoubleBinaryOperator
Represents an operation on two double value operators, and returns the result of a double value.
8
DoubleConsumer
Represents an operation that takes a double value parameter and does not return a result.
9
DoubleFunction<R>
Represents a method that accepts a double value parameter and returns the result
10
DoublePredicate
Represents a boolean value method with a double value parameter
11
DoubleSupplier
Represents the provider of a double value structure
12
DoubleToIntFunction
Accept a double type input and return an int type result.
13
DoubleToLongFunction
Accept a double type input and return a long type result
14
DoubleUnaryOperator
Accept a parameter of the same type as double and return value of the same type as double.
15
Function<T,R>
Accept an input parameter and return a result.
16
IntBinaryOperator
Accept two parameters of the same type int, and return value of the same type int.
17
IntConsumer
Accepts an input parameter of type int with no return value.
18
IntFunction<R>
Accepts an int type input parameter and returns a result.
19
IntPredicate
: accepts an int input parameter and returns the result of a Boolean value.
20
IntSupplier
No parameters, return an int type result.
21
IntToDoubleFunction
Accepts an int type input and returns a double type result.
22
IntToLongFunction
Accepts an int type input and returns a long type result.
23
IntUnaryOperator
Accept a parameter of type int, and return value of type int.
24
LongBinaryOperator
It accepts two parameters of the same type as long, and the return value type is long.
25
LongConsumer
Accepts an input parameter of type long with no return value.
26
LongFunction<R>
Accepts a long type input parameter and returns a result.
27
LongPredicate
R takes a long input parameter and returns a boolean type result.
28
LongSupplier
No parameter, return a value of result long type.
29
LongToDoubleFunction
Accepts a long type input and returns a double type result.
30
LongToIntFunction
Accepts a long type input and returns an int type result.
31
LongUnaryOperator
Accept a parameter of the same type long, and return value of the same type long.
32
ObjDoubleConsumer<T>
Accept an object type and a double type input parameter, no return value.
33
ObjIntConsumer<T>
Accept an object type and an int type input parameter, no return value.
34
ObjLongConsumer<T>
Accept an object type and a long type input parameter, no return value.
35
Predicate<T>
Accepts an input parameter and returns a boolean result.
36
Supplier<T>
No parameters, return a result.
37
ToDoubleBiFunction<T,U>
Accept two input parameters and return a result of double type
38
ToDoubleFunction<T>
Accept an input parameter and return a result of double type
39
ToIntBiFunction<T,U>
Accepts two input parameters and returns an int type result.
40
ToIntFunction<T>
Accepts an input parameter and returns an int type result.
41
ToLongBiFunction<T,U>
Takes two input parameters and returns a long result.
42
ToLongFunction<T>
Accepts an input parameter and returns a long result.
43
UnaryOperator<T>
Accept a parameter of type T and return value of type T.

Posted by Pikachu2000 on Mon, 23 Dec 2019 08:34:34 -0800