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