New Java 8 features - lambda

Keywords: Java Lambda

1. Introduction to lambda

1.1 introduction to lambda expression

  • Lambda expression is an anonymous function. We can understand lambda expression as a piece of code that can be passed (passing code like data). You can write more concise and flexible code. As one
    A more compact code style has improved the expression ability of Java language. JDK8 introduces a new operator "- >", which is called arrow operator or Lambda operator. The arrow operator will Lambda table
    The expression is divided into two parts:
  • Left: list of parameters for Lambda expression. The parameter list of the abstract method in the corresponding interface.
  • Right: the function to be performed in the Lambda expression, that is, Lambda
    Body. Implementation of abstract methods in corresponding interfaces

1.2 basic usage of lambda

  • Interface
public interface Bird {
    void fly(Integer times);
}

  • Three implementation methods
  • Note: Lambda expressions need the support of functional interfaces, which are interfaces with only one abstract method
package cn.knightzz.work;

import cn.knightzz.service.Bird;

public class LambdaTest {

    public static void main(String[] args) {
        Bird bird01 = new BirdImpl();
        bird01.fly(1000);

        // Method 2 of implementing the interface: anonymous inner class
        Bird bird02 = new Bird() {
            @Override
            public void fly(Integer times) {
                System.out.println("Mode II : The bird is flying : " + times + "s");
            }
        };
        bird02.fly(1000);

        // Method 3: lambda expression: (parameter 1, parameter 2,...) - > {}
        // TODO: Lambda expressions need the support of functional interfaces, which are interfaces with only one abstract method
        Bird bird03 = (param) -> {
            System.out.println("Mode III : The bird is flying : " + param + "s");
        };
        bird03.fly(1000);
    }
}

/**
 * Interface implementation mode I
 */
class BirdImpl implements Bird {

    /**
     * flight
     *
     * @param times flight time
     */
    @Override
    public void fly(Integer times) {
        System.out.println("Mode 1: The bird is flying : " + times + "s");
    }
}

2. Lambda basic grammar

  • We can use lambda syntax instead of anonymous method creation. Lambda syntax is as follows

  • If there is only one line of code in the body of the lambda method, {} can be omitted

    (Parameter 1,Parameter 2,...) -> {}
    
  • Note: Lambda expressions require functional interface support

2.1 functional interface

  • An interface with only one abstract method (a method that must be overridden) is called a functional interface. Note that the method must be overridden!!!, The default method does not have to be overridden, but we can override it!
  • The default modifier method can only be used in the interface (it can only be called by the object that implements the interface), and is marked by default in the interface
    Method is a common method, and the method body can be written directly.
  • You can use the annotation @ functional interface modifier to check whether it is a functional interface. If it is not a functional interface, an error will be reported
@FunctionalInterface
public interface Dog {
    /**
     * dog's bark
     *
     * @param dogName Dog's name
     */
    void yap(String dogName);

    // void flaw(); //  Non functional interfaces will report errors

    /**
     * The default method implements the Dog interface. It is not necessary to implement this method
     */
    default void fly() {
        System.out.println("Default method fly() ");
    }

    /**
     * By default, you can define multiple methods
     */
    default void flaw() {
        System.out.println("Default method flaw() ");
    }
}

  • Lambda expressions need the support of functional interfaces. In the past, the inheritance relationship of our whole java has been used for many years. In the new version of java, in order to cater to functional interfaces, only one abstract method in an interface will lead to the invalidation of many previous interfaces, and others cannot upgrade jdk. Therefore, the default method is provided. After jdk1.8, You can define default methods in the interface
  • Note that only one method in a functional interface must be overridden!!!, The default method does not have to be overridden, but we can override it!
  • Therefore, we can add default to other interfaces. Lambda only needs to implement functional interfaces
class BigDog implements Dog {

    /**
     * Functional interface
     *
     * @param dogName Dog's name
     */
    @Override
    public void yap(String dogName) {
        System.out.println("BigDog name is : " + dogName);
    }
	
    // All implemented are default interfaces
    @Override
    public void flaw() {
        System.out.println("One bigDog Catching");
    }
	
    // All implemented are default interfaces
    @Override
    public void fly() {
        System.out.println("One bigDog Flying");
    }
}

  • Some fixed interfaces can be set as the default interface and implemented. The interfaces that need to change according to specific business can be defined as functional interfaces to dynamically implement specific logic
public class FunctionInterfaceTest {

    public static void main(String[] args) {

        Dog dog = (name) -> {
            System.out.println("dog name is : " + name);
        };

        dog.yap("cat");
        dog.flaw();
        dog.fly();

        // This method can be rewritten according to the actual business requirements
        Dog dog02 = (name) -> {
            System.out.println("dog name is : " + name);
        };

        dog02.yap("cat");
        BigDog bigDog = new BigDog();
        bigDog.flaw();
        bigDog.fly();
        bigDog.yap("pig");
    }
}

3. Built in functional interface

Lambda's implementation depends on functional interfaces, which can be defined by ourselves. Of course, we can also use some functional interfaces already provided by JDK
Interfaces, which can basically meet our common operations, and have been widely used in frameworks such as collections, so we can use these interfaces directly.

  • Consumption type, supply type, function type and break type
    • Consumer void accept (T)
    • Supplier T get()
    • Function < T, R > R apply (T, t)
    • Predicate Boolean test (T)
  • Consumptive: only in but not out
    Supply type: start from scratch and cover the white wolf with empty hands
    Function type: reciprocity
    Conclusion line: appraisal review
  • Note: only the parameters and return values of the methods in the interface are concerned

3.1 Consumer interface

With a parameter, it will be used in the method body. For example, the forEach method in the Collection needs an implementation class object of the Consumer interface.

public class CollectionInterface {

    public static void main(String[] args) {
        // Consumer interface
        Collection<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("aaa2");
        list.add("aaa3");
        list.add("aaa4");
        // forEach(Consumer<? super T> action)
        list.forEach(item -> System.out.println(item));
    }
}

3.2 Supplier supply interface

public class SupplierInterface {

    public static void main(String[] args) {

        SupplierInterface supplierInterface = new SupplierInterface();
        List<Integer> numberList = supplierInterface.getNumberList(10, () -> (int) (Math.random() * 100));
        numberList.forEach(item -> System.out.println(item));
    }

    public List<Integer> getNumberList(int num, Supplier<Integer> data) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            Integer n = data.get();
            list.add(n);
        }
        return list;
    }
}

3.3 function < T, R > functional interface

  • The function calls our own business logic through apply(str)

  • Custom apply

     String result = functionalInterface.strHandler("abc", (str) -> {
                // Note: STR here is the str of function.apply(str)
                return str.toUpperCase();
    });
    
  • Core code

package cn.knightzz.inter;

import java.util.function.Function;

/**
 * @author knightzz98
 * @title: FunctionInterface
 * @projectName JavaBase
 * @description:
 * @date 2021/9/4 18:29
 */
public class FunctionInterface {

    public static void main(String[] args) {

        FunctionInterface functionalInterface = new FunctionInterface();

        String result = functionalInterface.strHandler("abc", (str) -> {
            // Note: STR here is the str of function.apply(str)
            return str.toUpperCase();
        });

        System.out.println("result = " + result);

    }

    /**
     * Process string
     * Function<String, String> : The first is the apply(param) parameter value type, and the second is the return value type
     *
     * @return Processed string
     */
    public String strHandler(String str, Function<String, String> function) {
        // Unified processing logic can be written here
        return function.apply(str);
    }
}

3.4 Predicate assertion interface

  • The return value of predict. Test (data) is of boolean type

  • The code we write is equivalent to a custom test(data) method

    List<String> strs = pre.filterStr(Arrays.asList(datas), (data) -> {
                // Write the logic of the predict. Test (data) method, and the return value is boolean
                return data.length() > 2;
            });
    
  • Core code

package cn.knightzz.inter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;

/**
 * @author knightzz98
 * @title: PredicateInterface
 * @projectName JavaBase
 * @description: Assertive interface
 * @date 2021/9/4 18:37
 */
public class PredicateInterface {

    public static void main(String[] args) {
        PredicateInterface pre = new PredicateInterface();
        String[] datas = new String[]{"aaaa", "bb", "ccc"};
        List<String> strs = pre.filterStr(Arrays.asList(datas), (data) -> {
            // Write the logic of the predict. Test (data) method, and the return value is boolean
            return data.length() > 2;
        });
        strs.forEach(item -> System.out.println(item));
    }

    public List<String> filterStr(List<String> datas, Predicate<String> predicate) {
        List<String> list = new ArrayList<>();
        for (String data : datas) {
            if (predicate.test(data)) {
                list.add(data);
            }
        }
        return list;
    }
}

4. Method reference

After a brief look, the performance has not improved, and the readability of the code has become poor. It is useless except that the code is short. It is predicted that you will be scolded if you use it. Temporarily define a directory and learn again after you use it

4.1. Object:: instance method name

4.2. Class:: static method name

4.3. Class: instance method name

4.4. Constructor reference

Posted by thunderbox on Sat, 04 Sep 2021 20:47:32 -0700