preface
The basis for using Lambda is that there must be a corresponding function interface (function interface refers to the interface with only one abstract method inside). This is consistent with the fact that Java is a strongly typed language, which means that you can't write Lambda expressions arbitrarily anywhere in the code. In fact, the type of Lambda is the type of the corresponding function interface. Another basis of Lambda expression is the type inference mechanism (emphasis). When the context information is sufficient, the compiler can infer the type of parameter table without explicit naming.
Reader benefits: Java core learning notes +2021 latest Real interview questions of large factories share!
1, Evolution process
A. Preparation of basic classes
package com.os.model; import java.util.Objects; public class Employee { private int id; private String name; private int age; private double salary; //Omit the generated getter and setter methods, and construct methods, toString methods, hashCode and equals methods } Copy code
B. Filter data
We need to set different methods according to different screening conditions, which increases a lot of code.
package com.os.test; import com.os.model.Employee; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Demo01 { private static List<Employee> emps = Arrays.asList( new Employee(101, "name of a fictitious monkey with supernatural powers", 18, 9999.99), new Employee(102, "Bajie", 59, 6666.66), new Employee(103, "Tang Monk", 28, 3333.33), new Employee(104, "Monk Sha", 8, 7777.77), new Employee(105, "White dragon horse", 38, 5555.55) ); public static void main(String[] args) { System.out.println("===>1.Screening age"); List<Employee> list = filterEmployeeAge(emps); for (Employee employee : list) { System.out.println(employee); } System.out.println("===>2.Screening salary"); list = filterEmployeeSalary(emps); for (Employee employee : list) { System.out.println(employee); } } /** * Demand: obtain the information of employees younger than 35 in the company * @param employeeList * @return */ public static List<Employee> filterEmployeeAge(List<Employee> employeeList){ List<Employee> list = new ArrayList<>(); for (Employee emp : employeeList) { if(emp.getAge() <= 35){ list.add(emp); } } return list; } /** * Demand: obtain the information of employees whose salary is greater than 5000 in the company * @param employeeList * @return */ public static List<Employee> filterEmployeeSalary(List<Employee> employeeList){ List<Employee> list = new ArrayList<>(); for (Employee emp : employeeList) { if(emp.getSalary() >= 5000){ list.add(emp); } } return list; } } Copy code
C. Code evolution: strategy design pattern
(1) Generic interface for defining filter criteria
package com.os.service; /** * Interface for data filtering criteria */ public interface ObjectDataPredicate<T> { boolean test(T t); } Copy code
(2) Implement classes to implement different filtering methods
Filter implementation classes by age
package com.os.service; import com.os.model.Employee; public class FilterEmployeeForAge implements ObjectDataPredicate<Employee> { @Override public boolean test(Employee employee) { return employee.getAge() <= 35; } } Copy code
Filter implementation classes by salary
package com.os.service; import com.os.model.Employee; public class FilterEmployeeForSalary implements ObjectDataPredicate<Employee> { @Override public boolean test(Employee employee) { return employee.getSalary() >= 5000; } } Copy code
(3) Implementation code of policy mode
public static List<Employee> filterEmployee(List<Employee> emps, ObjectDataPredicate<Employee> objectDataPredicate){ List<Employee> list = new ArrayList<>(); for (Employee employee : emps) { if(objectDataPredicate.test(employee)){ list.add(employee); } } return list; } Copy code
The complete code is as follows
package com.os.test; import com.os.model.Employee; import com.os.service.FilterEmployeeForAge; import com.os.service.FilterEmployeeForSalary; import com.os.service.ObjectDataPredicate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Demo02 { private static List<Employee> emps = Arrays.asList( new Employee(101, "name of a fictitious monkey with supernatural powers", 18, 9999.99), new Employee(102, "Bajie", 59, 6666.66), new Employee(103, "Tang Monk", 28, 3333.33), new Employee(104, "Monk Sha", 8, 7777.77), new Employee(105, "White dragon horse", 38, 5555.55) ); public static void main(String[] args) { List<Employee> list = filterEmployee(emps, new FilterEmployeeForAge());//Interface callback for (Employee employee : list) { System.out.println(employee); } System.out.println("------------------------------------------"); List<Employee> list2 = filterEmployee(emps, new FilterEmployeeForSalary());//Interface callback for (Employee employee : list2) { System.out.println(employee); } } public static List<Employee> filterEmployee(List<Employee> emps, ObjectDataPredicate<Employee> objectDataPredicate){ List<Employee> list = new ArrayList<>(); for (Employee employee : emps) { if(objectDataPredicate.test(employee)){ list.add(employee); } } return list; } } Copy code
There are too many implementation classes of this code
D. Code evolution: anonymous inner classes
package com.os.test; import com.os.model.Employee; import com.os.service.FilterEmployeeForAge; import com.os.service.FilterEmployeeForSalary; import com.os.service.ObjectDataPredicate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Demo03 { private static List<Employee> emps = Arrays.asList( new Employee(101, "name of a fictitious monkey with supernatural powers", 18, 9999.99), new Employee(102, "Bajie", 59, 6666.66), new Employee(103, "Tang Monk", 28, 3333.33), new Employee(104, "Monk Sha", 8, 7777.77), new Employee(105, "White dragon horse", 38, 5555.55) ); public static void main(String[] args) { List<Employee> list = filterEmployee(emps, new ObjectDataPredicate<Employee>() { @Override public boolean test(Employee employee) { return employee.getId() <= 103; } });//Interface callback for (Employee employee : list) { System.out.println(employee); } } public static List<Employee> filterEmployee(List<Employee> emps, ObjectDataPredicate<Employee> objectDataPredicate){ List<Employee> list = new ArrayList<>(); for (Employee employee : emps) { if(objectDataPredicate.test(employee)){ list.add(employee); } } return list; } } Copy code
Through the inner class, we can find that the core part of the whole code is one sentence, employee getId() <= 103
E. Code evolution: Lambda expressions
package com.os.test; import com.os.model.Employee; import com.os.service.ObjectDataPredicate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Demo04 { private static List<Employee> emps = Arrays.asList( new Employee(101, "name of a fictitious monkey with supernatural powers", 18, 9999.99), new Employee(102, "Bajie", 59, 6666.66), new Employee(103, "Tang Monk", 28, 3333.33), new Employee(104, "Monk Sha", 8, 7777.77), new Employee(105, "White dragon horse", 38, 5555.55) ); public static void main(String[] args) { /* List<Employee> list = filterEmployee(emps, new ObjectDataPredicate<Employee>() { @Override public boolean test(Employee employee) { return employee.getId() <= 103; } });//Interface callback */ List<Employee> list = filterEmployee(emps, (e) -> e.getAge() <= 35); for (Employee employee : list) { System.out.println(employee); } System.out.println("------------------------------------------"); List<Employee> list2 = filterEmployee(emps, (e) -> e.getSalary() >= 5000); for (Employee employee : list2) { System.out.println(employee); } } public static List<Employee> filterEmployee(List<Employee> emps, ObjectDataPredicate<Employee> objectDataPredicate){ List<Employee> list = new ArrayList<>(); for (Employee employee : emps) { if(objectDataPredicate.test(employee)){ list.add(employee); } } return list; } } Copy code
Lambda is an anonymous function. We can understand lambda expression as a piece of code that can be passed (pass the code like data). You can write more concise and flexible code. As a more compact code style, the language expression ability of Java has been improved.
2, Lambda basic grammar
Lambda expressions introduce a new syntax element and operator into the Java language. This operator is - >, which is called lambda operator or scissor operator. It divides lambda into two parts:
- Left: specifies all parameters required by Lambda expression (corresponding to formal parameters in the interface)
- Right: Specifies the Lambda body, that is, the function to be performed by the Lambda expression. (method body, you can infer the return value type)
A. Format 1: no parameter, no return value
package com.os.print.service; @FunctionalInterface//Define interface functions public interface Printer01 { void print(); } Copy code
package com.os.print.service; public class Demo01 { public static void main(String[] args) { //We can use your implementation class before Printer01 out = new Printer01() { @Override public void print() { System.out.println("Anonymous implementation class"); System.out.println("====>"+Math.random()); } }; out.print(); //Using Lambda expressions out = ()-> System.out.println("The method body has only one line, and braces can be omitted"); out.print(); out = ()->{ System.out.println("There are many method bodies, which need to be handled with curly braces"); System.out.println("====>"+Math.random()); }; out.print(); } } Copy code
B. Format 2: there is one parameter and no return value
package com.os.print.service; @FunctionalInterface//Define interface functions public interface Printer02<T> { void print(T t); } Copy code
public class Demo02 { public static void main(String[] args) { //Inferring the type of parameter e through generics Printer02<Employee> out01 = (e)-> System.out.println(e); out01.print(new Employee(999,"name of a fictitious monkey with supernatural powers",19,25000)); Printer02<Integer> out2 = (e)-> System.out.println(e); out2.print(999); Printer02<String> out3 = (e)-> System.out.println(e); out3.print("Journey to the West"); } } Copy code
C. Format 3: if there is only one parameter, parentheses can be omitted
package com.os.print.service; import com.os.model.Employee; public class Demo02 { public static void main(String[] args) { //Inferring the type of parameter e through generics Printer02<Employee> out01 = e-> System.out.println(e); out01.print(new Employee(999,"name of a fictitious monkey with supernatural powers",19,25000)); Printer02<Integer> out2 = e-> System.out.println(e); out2.print(999); Printer02<String> out3 = e-> System.out.println(e); out3.print("Journey to the West"); } } Copy code
D. Format 4: there are more than two parameters, return values, and multiple statements in the Lambda body
The function interface test of the system is as follows:
package com.os.print.service; import com.os.model.Employee; import java.util.Comparator; public class Demo03 { public static void main(String[] args) { /* public interface Comparator<T> { } * */ Comparator<Integer> comparator = (x,y)->{ System.out.println("Interface function method"); return Integer.compare(x,y); }; } } Copy code
Custom function interface method:
package com.os.print.service; @FunctionalInterface//Define interface functions public interface Printer03<T> { T print(T t1,T t2); } Copy code
package com.os.print.service; import com.os.model.Employee; import java.util.Comparator; public class Demo03 { public static void main(String[] args) { Printer03<String> out01 = (s1,s2)->{ String str = s1.concat(s2); return str.toUpperCase(); }; System.out.println(out01.print("abc","efg")); } } Copy code
User defined function interface method has two parameters:
package com.os.print.service; @FunctionalInterface//Define interface functions public interface Printer04<T,R> { R print(T t1, R t2); } Copy code
package com.os.print.service; import com.os.model.Employee; public class Demo04 { public static void main(String[] args) { Printer04<String, Employee> out = (name,e)->{ e.setName(name); return e; }; Employee employee = out.print("Journey to the West",new Employee()); System.out.println(employee); } } Copy code
E. Format 5: if there is only one statement in Lambda body, return and braces can be omitted
package com.os.print.service; import com.os.model.Employee; import java.util.Comparator; public class Demo04 { public static void main(String[] args) { Comparator<Integer> comparator = (x, y)->Integer.compare(x,y); System.out.println(comparator.compare(1,2)); Printer04<String, Employee> out = (name,e)->e; Employee employee = out.print("Journey to the West",new Employee()); System.out.println(employee); } } Copy code
F. Format 5: the data type of the parameter list of Lambda expression can be omitted, because the JVM compiler infers the data type through the context, that is, "type inference"
(Integer x, Integer y) -> Integer.compare(x, y); //This is not generally used Copy code
The parameter types in the above Lambda expressions are inferred by the compiler. There is no need to specify the type in Lambda expression, and the program can still be compiled. This is because javac infers the type of parameter in the background according to the context of the program. The type of Lambda expression depends on the context and is inferred by the compiler. This is called "type inference"
lambda syntax is summarized as follows:
- Couplet above: a parenthesized province is encountered on the left and right
- Second line: infer type province on the left
- Banner: save if you can
3, Functional interface
-
An interface that contains only one abstract method is called a functional interface.
-
You can create the object of this interface through Lambda expression.
- (if the Lambda expression throws a checked exception, the exception needs to be declared on the abstract method of the target interface).
-
Set @ FunctionalInterface annotation on any functional interface to check whether it is a functional interface. At the same time, javadoc will also contain a declaration that this interface is a functional interface.
In the above example, we have defined functional interfaces, but we can't define functional interfaces every time. It's too troublesome! Therefore, Java has built-in functional interfaces in Java util. Function package
A.Predicate assertion interface
@FunctionalInterface public interface Predicate<T> { boolean test(T t); } Copy code
package com.os.print.service; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; public class Demo05 { public static void main(String[] args) { List<String> list = Arrays.asList("Hello", "pangsir", "Lambda", "www", "ok"); List<String> strList = filterStr(list, (s) -> s.length() > 3); for (String str : strList) { System.out.println(str); } } //Requirement: put the strings that meet the conditions into the collection public static List<String> filterStr(List<String> list, Predicate<String> pre){ List<String> strList = new ArrayList<>(); for (String str : list) { if(pre.test(str)){ strList.add(str); } } return strList; } } Copy code
B. Function < T, R > functional interface
@FunctionalInterface public interface Function<T, R> { R apply(T t); } Copy code
package com.os.print.service; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Function; import java.util.function.Predicate; public class Demo06 { public static void main(String[] args) { String newStr = strHandler("\t\t\t Journey to the West Monkey King ", (str) -> str.trim()); System.out.println(newStr); String subStr = strHandler("Journey to the West Monkey King", (str) -> str.substring(2, 5)); System.out.println(subStr); } //Requirements: used to process strings public static String strHandler(String str, Function<String, String> fun){ return fun.apply(str); } } Copy code
C.Supplier supply interface
@FunctionalInterface public interface Supplier<T> { T get(); } Copy code
package com.os.print.service; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; public class Demo07 { public static void main(String[] args) { List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100)); for (Integer num : numList) { System.out.println(num); } } //Requirement: generate a specified number of integers and put them into the set public static List<Integer> getNumList(int num, Supplier<Integer> sup){ List<Integer> list = new ArrayList<>(); for (int i = 0; i < num; i++) { Integer n = sup.get(); list.add(n); } return list; } } Copy code
D.Consumer consumer interface
@FunctionalInterface public interface Consumer<T> { void accept(T t); } Copy code
package com.os.print.service; import java.util.function.Consumer; public class Demo08 { public static void main(String[] args) { happy(10000, (m) -> System.out.println("Shopping consumption:" + m + "element")); } public static void happy(double money, Consumer<Double> con){ con.accept(money); } } Copy code
java. util. There are many useful functional interfaces under the function package
Functional interface | Parameter type | Return type | purpose |
---|---|---|---|
Consumer consumer interface | T | void | Apply operations to objects of type T, including methods: void accept (T) |
Supplier supply interface | nothing | T | Return an object of type T, including methods: T get(); |
Function < T, R > functional interface | T | R | Apply an action to an object of type T. The result is an object of type R. Methods: R apply(T t); |
Predicate type interface | T | boolean | Determines whether an object of type T satisfies a constraint. boolean value. Including method boolean test (T); |
BiFunction<T,U,R> | T,U | R | The type of operation is u, and the return result is t. The inclusion method is: R apply (T, T,U); |
UnaryOperator | T | T | Performs a unary operation on an object of type T and returns the result of type T. The inclusion method is T apply(Tt); |
BinaryOperator | T,T | T | Performs a binary operation on an object of type T and returns the result of type T. The inclusion method is T apply(Tt1,Tt2); |
BiConsumer<T,U> | T,U | void | Apply operations to parameters of type T,U. The containing method is void accept (T, T,U) |
ToIntFunctionToLongFunctionToDoubleFunction | T | intlongdouble | Functions that calculate the values of int, long, double and |
IntFunctionLongFunctionDoubleFunction | intlongdouble | R | The parameters are functions of type int, long and double respectively |
4, Method reference
When the operation to be passed to the Lambda body has an implemented method, you can use the method reference!
Method reference: use the operator "::" to separate the method name from the name of the object or class.
- Object:: instance method
- Class:: static method
- Class:: instance method
be careful:
-
① The parameter list and return value type of the method referenced by the method reference should be consistent with the parameter list and return value type of the abstract method in the functional interface! Copy code
-
② If the first parameter in Lambda's parameter list is the caller of the instance method and the second parameter (or no parameter) is the parameter of the instance method, the format: ClassName::MethodName copy the code
A. Object reference:: instance method name
package com.os.print.service; import com.os.model.Employee; import java.util.function.Supplier; public class Demo09 { public static void main(String[] args) { Employee emp = new Employee(101, "Zhang San", 18, 9999.99); Supplier<String> sup = () -> emp.getName(); System.out.println(sup.get()); System.out.println("----------------------------------"); Supplier<String> sup2 = emp::getName; System.out.println(sup2.get()); } } Copy code
B. Class:: static method name
package com.os.print.service; import java.util.function.BiFunction; import java.util.function.Supplier; public class Demo10 { public static void main(String[] args) { BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y); System.out.println(fun.apply(1.5, 22.2)); System.out.println("--------------------------------------------------"); BiFunction<Double, Double, Double> fun2 = Math::max; System.out.println(fun2.apply(1.2, 1.5)); } } Copy code
C. Class:: instance method name
package com.os.print.service; import com.os.model.Employee; import java.util.function.BiFunction; import java.util.function.BiPredicate; import java.util.function.Function; public class Demo11 { public static void main(String[] args) { BiPredicate<String, String> bp = (x, y) -> x.equals(y); System.out.println(bp.test("abcde", "abcde")); System.out.println("-----------------------------------------"); BiPredicate<String, String> bp2 = String::equals; System.out.println(bp2.test("abc", "abc")); System.out.println("-----------------------------------------"); Function<Employee, String> fun = (e) -> e.getName(); System.out.println(fun.apply(new Employee())); System.out.println("-----------------------------------------"); Function<Employee, String> fun2 = Employee::getName; System.out.println(fun2.apply(new Employee())); } } Copy code
If the first parameter in Lambda's parameter list is the caller of the instance method and the second parameter (or no parameter) is the parameter of the instance method, the format is: ClassName::MethodName
D. Constructor reference ClassName::new
Format: ClassName::new is combined with functional interface and is automatically compatible with methods in functional interface. The constructor reference can be assigned to the defined method, and the constructor parameter list should be consistent with the parameter list of the abstract method in the interface!
package com.os.print.service; import com.os.model.Employee; import java.util.function.BiFunction; import java.util.function.BiPredicate; import java.util.function.Function; public class Demo12 { public static void main(String[] args) { Function<String, Employee> fun = Employee::new; System.out.println(fun.apply("name of a fictitious monkey with supernatural powers")); BiFunction<String, Integer, Employee> fun2 = Employee::new; System.out.println(fun2.apply("Bajie",18)); } } Copy code
E. Array reference
package com.os.print.service; import com.os.model.Employee; import java.util.function.BiFunction; import java.util.function.Function; public class Demo13 { public static void main(String[] args) { Function<Integer, String[]> fun = (e) -> new String[e]; String[] strs = fun.apply(10); System.out.println(strs.length); System.out.println("--------------------------"); Function<Integer, Employee[]> fun2 = Employee[] :: new; Employee[] emps = fun2.apply(20); System.out.println(emps.length); } } Pay attention to official account: Kirin reform bug Share 2021 gold three silver four Java Summary collection of interview questions!