This is my first day of the genwen challenge
To be able to use a Lambda, you must have a corresponding function interface (an interface that has only an abstract method inside it). This is consistent with the fact that Java is a strongly typed language, which means you can’t arbitrarily write Lambda expressions anywhere in your code. The type of Lambda is actually the type of the corresponding function interface. Lambda expressions also rely on the type inference mechanism (important), which allows the compiler to infer the type of the argument table without explicitly naming it, if sufficient context information is available.
1. Evolutionary 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 getteer and setter methods, constructor, toString, hashCode, equals methods
}
Copy the code
B. Filter data
We need to set up different methods according to different filtering conditions, increasing 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."The wu is empty".18.9999.99),
new Employee(102."Eight quit".59.6666.66),
new Employee(103."Tang's monk".28.3333.33),
new Employee(104."Sand monk".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 salaries");
list = filterEmployeeSalary(emps);
for(Employee employee : list) { System.out.println(employee); }}/** * Need: Get information about employees in the company who are younger than 35 *@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: Get information on employees whose salaries are above 5000 *@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); }}returnlist; }}Copy the code
C. Code evolution: Strategic design patterns
(1) Generic interfaces that define filtering conditions
package com.os.service;
/** * Interface for data filtering criteria */
public interface ObjectDataPredicate<T> {
boolean test(T t);
}
Copy the code
(2) implementation classes to achieve different screening 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 the 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 the code
(3) The implementation code of the strategy 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 the 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."The wu is empty".18.9999.99),
new Employee(102."Eight quit".59.6666.66),
new Employee(103."Tang's monk".28.3333.33),
new Employee(104."Sand monk".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); }}returnlist; }}Copy the code
There are too many implementation classes for 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."The wu is empty".18.9999.99),
new Employee(102."Eight quit".59.6666.66),
new Employee(103."Tang's monk".28.3333.33),
new Employee(104."Sand monk".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); }}returnlist; }}Copy the code
Using the inner class, we can see that the core part of the entire code is the 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."The wu is empty".18.9999.99),
new Employee(102."Eight quit".59.6666.66),
new Employee(103."Tang's monk".28.3333.33),
new Employee(104."Sand monk".8.7777.77),
new Employee(105.White Dragon Horse.38.5555.55));public static void main(String[] args) {
/* List
list = filterEmployee(emps, new ObjectDataPredicate
() { @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); }}returnlist; }}Copy the code
Lambda is an anonymous function, and we can think of a Lambda expression as a piece of code that can be passed (passing code like data). You can write cleaner, more flexible code. As a more compact code style, the language expression ability of Java has been improved.
Basic syntax for Lambda
Lambda expressions introduce a new syntactic element and operator into the Java language. The operator is ->, which is called the Lambda or clipping operator. It breaks Lambda into two parts:
- Left: Specifies all the parameters required by the Lambda expression (corresponding to the parameters in the interface)
- Right: specifies the body of the Lambda, which is the function that the Lambda expression is to perform. (Method body, the return value type can be inferred)
A. Format 1: No parameter, no return value
package com.os.print.service;
@FunctionalInterface// Define the interface function
public interface Printer01 {
void print(a);
}
Copy the code
package com.os.print.service;
public class Demo01 {
public static void main(String[] args) {
// Previously we could have used you to implement the class
Printer01 out = new Printer01() {
@Override
public void print(a) {
System.out.println("Anonymous implementation class");
System.out.println("= = = = >"+Math.random()); }}; out.print();// Use Lambda expressions
out = ()-> System.out.println("Method body is only one line, you can omit curly braces.");
out.print();
out = ()->{
System.out.println("There's a lot of method bodies, so I need to use curly braces.");
System.out.println("= = = = >"+Math.random()); }; out.print(); }}Copy the code
B. Format 2: One argument, no return value
package com.os.print.service;
@FunctionalInterface// Define the interface function
public interface Printer02<T> {
void print(T t);
}
Copy the code
public class Demo02 {
public static void main(String[] args) {
// Infer the type of parameter e from generics
Printer02<Employee> out01 = (e)-> System.out.println(e);
out01.print(new Employee(999."The wu is empty".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 the code
C. Format 3: If there is only one parameter, the parentheses can be omitted
package com.os.print.service;
import com.os.model.Employee;
public class Demo02 {
public static void main(String[] args) {
// Infer the type of parameter e from generics
Printer02<Employee> out01 = e-> System.out.println(e);
out01.print(new Employee(999."The wu is empty".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 the code
D. Format 4: More than two arguments, return values, and multiple statements in the Lambda body
Use the system some function interface test 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
{ } * */
Comparator<Integer> comparator = (x,y)->{
System.out.println("Interface function method");
returnInteger.compare(x,y); }; }}Copy the code
Custom function interface methods:
package com.os.print.service;
@FunctionalInterface// Define the interface function
public interface Printer03<T> {
T print(T t1,T t2);
}
Copy the 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 the code
The custom function interface method takes two parameters:
package com.os.print.service;
@FunctionalInterface// Define the interface function
public interface Printer04<T.R> {
R print(T t1, R t2);
}
Copy the 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.newEmployee()); System.out.println(employee); }}Copy the code
E. Format 5: If there is only one statement in the Lambda body, the 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.newEmployee()); System.out.println(employee); }}Copy the code
F. Format 5: The data type of the argument list of a Lambda expression can be omitted because the JVM compiler infer from the context that the data type, known as “type inference”
(Integer x, Integer y) -> Integer.compare(x, y); // This is not the way to write it
Copy the code
The types of arguments in Lambda expressions above are inferred by the compiler. Programs can compile without specifying a type in a Lambda expression, because Javac behind the scenes deduces the type of the argument based on the context of the program. The type of a Lambda expression is context-dependent and inferred by the compiler. This is called “type inference”
The syntax of lambda is summarized as follows:
- Top line: left and right in a parenthesis save
- Next link: left inferred type save
- Hengpi: can province province
Functional interface
-
An interface that contains only one abstract method is called a functional interface.
-
You can use Lambda expressions to create objects for this interface.
- If a Lambda expression throws a checked exception, the exception needs to be declared on the abstract method of the target interface.
-
Setting the @functionalinterface annotation on any FunctionalInterface checks if it is a FunctionalInterface, and javadoc includes a declaration that the interface is a FunctionalInterface.
We’ve already defined functional interfaces in the examples above, but we can’t always do it ourselves. It’s too much work! So, Java has built-in functional interfaces under the java.util. Function package
A. predicate <T> assertion interface
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
Copy the 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); }}// Requirements: put the string that meets the criteria 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); }}returnstrList; }}Copy the code
B. Connection <T,R> functional interface
@FunctionalInterface
public interface Function<T.R> {
R apply(T t);
}
Copy the 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: The Monkey King", (str) -> str.substring(2.5));
System.out.println(subStr);
}
// Requirement: Used to process strings
public static String strHandler(String str, Function<String, String> fun){
returnfun.apply(str); }}Copy the code
C. Upplier <T> Supply interface
@FunctionalInterface
public interface Supplier<T> {
T get(a);
}
Copy the 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); }}// Demand: generate a specified number of integers and put them into the collection
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);
}
returnlist; }}Copy the code
D.Consumer<T> consumer interface
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
Copy the 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 + "Yuan"));
}
public static void happy(double money, Consumer<Double> con){ con.accept(money); }}Copy the code
The java.util.function package has many useful functional interfaces
Functional interface | The parameter types | The return type | use |
---|---|---|---|
Consumer<T> Consumer interface |
T | void | Apply an operation to an object of type T, including methods: void accept(T t) |
Supplier<T> Supply interface |
There is no | T | Return an object of type T, containing the method T get(); |
Function<T, R> Functional interface |
T | R | Apply the operation to an object of type T. Results in an object of type R. Method: R apply(T T); |
Predicate<T> Stereotyped interface |
T | boolean | Determine whether an object of type T satisfies a constraint, Boolean value. Boolean test(T T); |
BiFunction<T,U,R> |
T,U | R | Apply an operation to a parameter of type T,U, and return a result of type R. R apply(T T,U U); |
UnaryOperator<T> |
T | T | Performs unary operation on an object of type T and returns a result of type T. Include method is T apply(Tt); |
BinaryOperator<T> |
T,T | T | Performs a binary operation on an object of type T and returns a result of type T. T apply(Tt1,Tt2); |
BiConsumer<T,U> |
T,U | void | Apply the operation to parameters of type T and U. Void accept(T T,U U) |
ToIntFunction<T> ToLongFunction<T> ToDoubleFunction<T> |
T | int long double |
Function that evaluates int, long, double, and value, respectively |
IntFunction<R> LongFunction<R> DoubleFunction<R> |
int long double |
R | Functions that take int, long, and double, respectively |
4. Method reference
When passing an operation to a Lambda body that already has a method implemented, use a method reference!
Method references: Use the “::” operator to separate the method name from the object or class name.
- Object :: instance method
- Class :: static methods
- Class :: instance methods
Note:
(1) < strong style = "color: red; The parameter list and return value type of the method referenced by the method reference need to be the same as the parameter list and return value type of the abstract method in the functional interface! </strong>Copy the code
If the first argument in the Lambda argument list is the caller to the instance method and the second argument (or no argument) is the argument to the instance method, the format is ClassName::MethodNameCopy 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".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 the 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 the 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(newEmployee())); }}Copy the code
If the first argument in the Lambda argument list is the caller to the instance method and the second argument (or no argument) is the argument to the instance method, the format is ClassName::MethodName
D. The constructor references ClassName::new
Format: ClassName::new combines with functional interfaces, automatically compatible with methods in functional interfaces. Constructor references can be assigned to defined methods, and the constructor argument list must match the argument 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("The wu is empty"));
BiFunction<String, Integer, Employee> fun2 = Employee::new;
System.out.println(fun2.apply("Eight quit".18)); }}Copy the code
E. Array references
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); }}Copy the code