Why use Lamdba expressions

Let me give you an example

Use anonymous inner classes

    public void test1(a){
        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                returnInteger.compare(o2,o1); }}; }Copy the code

That’s a lot of code, but in one sentence, Integer.compare(O2,o1)

Using Lambda expressions

   public void test2(a){
        Comparator<Integer> com = (o1, o2) -> Integer.compare(o1, o2);
    }
Copy the code

Isn’t that convenient. But there may be some people who think that there is no great convenience. So here’s another example to introduce Lambda expressions.

Create an Employee class with name, age, and salary attributes

public class Employee {
    private String name;
    private int age;
    private double salary;

    public Employee(a) {}public Employee(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    public String getName(a) {
        return name;
    }
    public int getAge(a) {
        return age;
    }
    public double getSalary(a) {
        return salary;
    }

    @Override
    public String toString(a) {
        return "name='" + name + '\' ' +
                ", age=" + age +
                ", salary="+ salary; }}Copy the code
  • Requirement 1: Obtain information about employees older than 35

We’re simulating a database, so prepare a List collection

// Arrays.aslist Converts Arrays to collections
List<Employee> employees = Arrays.asList(
    new Employee("Zhang".18.9999.99),
    new Employee("Bill".38.5555.55),
    new Employee("Fifty".50.6666.66),
    new Employee("Daisy".16.3333.33),
    new Employee("Cropland 7".8.7777.77));Copy the code

Now that there is demand, we must develop it

  /** * Obtain information about employees older than 35 *@param list
     * @return* /
    public List<Employee> findEmployeesByAge(List<Employee>list){
        List<Employee>emps = new ArrayList<>();
        for(Employee emp : list){
            if(emp.getAge() > 35){ emps.add(emp); }}return emps;
    }
Copy the code

And to wave development self test

 @Test
    public void test3(a){
        List<Employee> employeesByAge = findEmployeesByAge(employees);
        for(Employee employee : employeesByAge) { System.out.println(employee); }} The output is name='bill', age=38, salary=5555.55
name='Cathy', age=50, salary=6666.66
Copy the code

Perfect!!!!!! The alacrity. Finish the job. Then came another demand

  • Requirement 2: Obtain information about employees in the company whose salary is greater than 5000
 public List<Employee> findEmployeesBySalary(List<Employee>list){
        List<Employee>emps = new ArrayList<>();
        for(Employee emp : list){
            if(emp.getSalary() > 5000){ emps.add(emp); }}return emps;
    }
Copy the code

When you finish it, you find out, shit… I just changed the method name and the criteria, and you’re smart enough to realize that this code can’t be written that way. Why can’t you write like that! If one of your best clients, **, suddenly comes in with a demand for someone older than 20, with a salary greater than 3,000. How to do this. Continue adding methods? No way!

Optimization 1: The strategic pattern of design patterns

Create an interface for querying behavior

public interface MyPredicate<T> {
    public boolean test(a);
}
Copy the code

And create related implementation classes to represent different behaviors: (age > 35 and salary > 5000, respectively)

// Obtain information about employees older than 35
public class FindEmployeesByAge implements MyPredicate<Employee>{
    @Override
    public boolean test(Employee emp) {
        return emp.getAge() > 35; }}// Obtain information about employees in the company whose salary is greater than 5000
public class FindEmployeesBySalary implements MyPredicate<Employee>{
    @Override
    public boolean test(Employee emp) {
        return emp.getSalary() > 5000; }}Copy the code

In the Test class, provide a generic method for the outside

public List<Employee> filterEmployees(List<Employee>list,MyPredicate<Employee>mp){
    List<Employee>emps = new ArrayList<>();
    for(Employee emp : list){
        if(mp.test(emp)){  // Key codeemps.add(emp); }}return emps;
}
Copy the code

After writing for so long, test yourself

  @Test
   public void test4(a){
       // Pass FindEmployeesByAge to get information about employees older than 35
       List<Employee> employees = filterEmployees(this.employees, new FindEmployeesByAge());
       for(Employee employee : employees) { System.out.println(employee); }} The output is name='bill', age=38, salary=5555.55
name='Cathy', age=50, salary=6666.66
Copy the code

If you want to test the information of employees whose salary is greater than 5000, Replace FindEmployeesByAge with FindEmployeesByAge in filterEmployees(this.Employees, new FindEmployeesByAge()) to FindEmployeesBySalary

If you want to create an implementation class for a requirement, do you have any other methods?

Optimization 2: Anonymous inner classes

Benefits: You don’t need to create a concrete implementation class for the interface (although you do need the MyPredicate interface and filterEmployees() method):

  @Test
    public void test5(a){
        List<Employee> employees = filterEmployees(this.employees, new MyPredicate<Employee>() {
            @Override
            public boolean test(Employee employee) {
                return employee.getAge() >= 18; }});for(Employee employee : employees) { System.out.println(employee); }} The output is name='Joe', age=18, salary=9999.99
name='bill', age=38, salary=5555.55
name='Cathy', age=50, salary=6666.66
Copy the code

Optimization three: Lambda expressions

Hahaha, the optimization goes back to the first example (*^▽^*). The Lambda expression eliminates the useless code of anonymous inner classes, improving the code’s neatness and readability (note that the filterEmployees method is still needed).

 @Test
    public void test6(a){
        List<Employee> employees = filterEmployees(this.employees, (e) -> e.getAge() > 15);
        for(Employee employee : employees) { System.out.println(employee); }} The output is name='Joe', age=18, salary=9999.99
name='bill', age=38, salary=5555.55
name='Cathy', age=50, salary=6666.66
name='Daisy', age=16, salary=3333.33
Copy the code
Take this piece of codenew MyPredicate<Employee>() {
            @Override
            public boolean test(Employee employee) {
                return employee.getAge() >= 18; }}); (e) -> equetage () > (e) -> equetage () >15
Copy the code

Optimization 4: Use the Stream API

In this way, we don't need all the methods we created above, including interfaces, implementation classes. Of course, the data is still needed. (Just a word here)

  @Test
    public void test7(a){
        employees.stream()
                .filter((e) -> e.getAge() > 35) .forEach(System.out::println); } The output is name='bill', age=38, salary=5555.55
name='Cathy', age=50, salary=6666.66
Copy the code

Basic syntax for Lambda expressions

Java8 introduced a new operator, “->”. This operator is called the arrow operator or the Lambda operator. The arrow operator splits a Lambda expression into two parts:

  • Left: The argument list of the Lambda expression, that is, the argument list of the abstract method in the interface
  • Right: The functionality required to perform in a Lambda expression (i.e., the Lambda body), corresponding to the implementation of the abstract method

Note: Lambda expressions require support for functional interfaces. A functional interface is one in which there can be only one abstract method

Basic grammar

Format 1: No parameter or return value

  @Test
    public void test1(a){
        Runnable runnable = new Runnable() {
            @Override
            public void run(a) {
                System.out.println("Common Runnable"); }}; runnable.run(); System.out.println("============= I am the dividing line =============");

        Runnable runnable1 = () -> System.out.println("Lambda Runnable"); runnable1.run(); } output: ordinary Runnable = = = = = = = = = = = = = I'm line = = = = = = = = = = = = = Lambda RunnableCopy the code

Format 2: one parameter, no return value (If there is only one argument in the argument list, the parentheses can be omitted)


    @Test
    public void test2(a){
        //Consumer will be introduced later
        //Consumer con = (x) -> System.out.println(x);
    	Consumer con = x -> System.out.println(x);
        con.accept("NiuBi Class"); } Output: NiuBi ClassCopy the code

Format 3: Multiple arguments, a return value, and a Lambda body with only one statement (The braces and return can be omitted)

@Test
public void test3(a){
   Comparator<Integer> com = (Integer x,Integer y) -> Integer.compare(x, y);
   int compare = com.compare(12.333); System.out.println(compare); } Output: -1
Copy the code

Format 4: multiple arguments, a return value, a Lambda body with multiple statements (You want to put braces around it, and you want to say return)

@Test
  public void test4(a){
    Comparator<Integer>com = (Integer x,Integer y) -> {
        System.out.println("Functional interface");
        return Integer.compare(x,y);
    };
  // Execute the com.pare code before the Lambda body is executed
    int compare = com.compare(1211.333); System.out.println(compare); } Output: functional interface1
Copy the code

Format 5: Type inference

The data type of the argument list of a Lambda expression can be omitted because the JVM compiler can infer the data type from the context. This process is called “type inference”, for example :(Integer x,Integer y) -> Integer.compare(x,y); This can be abbreviated as (x,y) -> Integer.compare(x,y);

Functional interface

  • An interface with only one abstract method is called a functional interface

  • Use the annotation @functionLInterface to check if it is a functional interface

Next, let’s create a functional interface that performs + – * / on a number

@FunctionalInterface
public interface MyFun {
    Integer getValue(Integer num);
}
Copy the code

Add a generic method to the Test class:

 public Integer operation(Integer num,MyFun mf){
        return mf.getValue(num);
    }
Copy the code

Testing:

 @Test
    public void test5(a){
        System.out.println(this.operation(100,(x) -> x * x ));
    }
Copy the code

One more word:

The arrow operator splits the Lambda expression into two parts:

  • Left: The argument list of the Lambda expression, that is, the argument list of the abstract method in the interface. Integer getValue(Integer num); That’s num.

  • Right: The functionality required to perform in a Lambda expression (i.e., the Lambda body), corresponding to the implementation of the abstract method. The equivalent of

  @Override
      public Integer getValue(Integer num) {
          return num * num;
      }
Copy the code

Four built-in functional interfaces

We found it too cumbersome to write our own functional interface to use Lambda, so Java8 provides four built-in functional interfaces, with only a small number of special cases where we need to define our own

  • Consumer<T>Consumer interfacevoid accept(T t);: Applies an operation to an object of type T
  • Supplier<T>Supply interfaceT get();: Returns an object of type T
  • Function<T, R>Functional interfaceR apply (T t);: Applies an operation to an object of type T and returns the result, which is an object of type R
  • Predicate<T>Predicate interfaceboolean test(T t);: Determines whether an object of type T satisfies a constraint and returns a Boolean value that satisfies true

Consumer<T>Consumer interfacevoid accept(T t);

@Test
    public void test1(a) {
       1 / / examples
        happy(1000,(x)->System.out.println("You're spending money on me." + x + "Yuan"));
        
        2 / / examples
        List<String> list = Arrays.asList("1"."2"."3");
        list.forEach((obj) -> System.out.println(obj));
    }

 public void happy(Integer i, Consumer<Integer> con){
     // Run the Lamdba body
       con.accept(i);
   }
Copy the code

Supplier<T>Supply interfaceT get();

Requirement: To produce a specified number of integers and put them into a collection

@Test
   public void test2(a){
       List<Integer> numList = getNumList(5, () - > (int) (Math.random() * 100));
       numList.forEach((obj)->System.out.println(obj));
   }

    public List<Integer> getNumList(int num, Supplier<Integer> sup){
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            // Run the Lamdba body
            Integer value = sup.get();
            list.add(value);
        }
        return list;
    }
Copy the code

Function<T, R>Functional interfaceR apply (T t);

 @Test
    public void test3(a){
        // Remove Spaces
        System.out.println(strHandler(" gongj ",(str) -> str.trim()));
        // Convert case
        System.out.println(strHandler("gongj", (str) -> str.toUpperCase()));
    }

    private String strHandler(String str, Function<String,String> fun){
        // Run the Lamdba body
        return fun.apply(str);
    }
Copy the code

Predicate Predicate Predicate interface Boolean test(T T);

@Test
    public void test4(a){
        List<String> list = Arrays.asList("gongj"."yuanj"."xdd");
        System.out.println( filterStr(list,(str) -> str.length() > 3));
    }
    // Judge a string with a length greater than 3
    public List<String> filterStr(List<String> strs, Predicate<String> pre){
        ArrayList<String> arrayList = new ArrayList<>();
        for (String str : strs) {
            // Run the Lamdba body
            if(pre.test(str)){ arrayList.add(str); }}return arrayList;
    }
Copy the code

Other types of functional interfaces

  • If you have any questions or errors in this article, please feel free to comment. If you find this article helpful, please click like and follow.