Day_25 [Java basics] detailed explanation of Lambda expression, functional interface, constructor reference and array reference of new features of Java 8 [source code attached]

Posted by Jennie on Thu, 02 Dec 2021 00:44:55 +0100

Java 8 (also known as jdk 1.8) was released by oracle in March 2014. It can be regarded as the most revolutionary version since Java 5. Java 8 brings a lot of new features to the Java language, compiler, class library, development tools and JVM.

1, Lambda expression

Let's look at two examples:

@Test
public void test01(){
    Runnable r1 = new Runnable() {
        @Override
        public void run() {
            System.out.println("I love Java...");
        }
    };
    r1.run();//Just run the overridden run() method, not multithreading
    //Using Lambda expressions
    Runnable r2 = () -> {System.out.println("I love Java 8 New features...");};
    r2.run();
}

@Test
public void test02(){
    Comparator<Integer> comparator = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1,o2);
        }
    };
    int compare = comparator.compare(30, 28);
    System.out.println(compare);//1
    //Using Lambda expressions
    Comparator<Integer> comparator1 = (o1,o2) -> compare(o1,o2);
    int compare1 = comparator1.compare(25, 36);
    System.out.println(compare1);
    //Method reference
    Comparator<Integer> comparator2 = Integer::compare;
    int compare2 = comparator2.compare(22, 36);
    System.out.println(compare2);
}


Lambba is an anonymous function. Lambda can be understood as a piece of code that can be passed (pass the code like data). As can be seen from the example, lambda has a fixed format:
Example: (o1, o2) - > integer. Compare (o1, o2)
Format:
->: Lambda operator
(): Lambda formal parameter list (in fact, it is the formal parameter list of abstract methods in the interface)
{}: Lambda body (actually the method body of the overridden abstract method)
Lambda essence: as an example of functional interface
1. Syntax format 1: no parameter and no return value

@Test
public void test01(){
    Runnable r1 = new Runnable() {
        @Override
        public void run() {
            System.out.println("I love Java...");
        }
    };
    r1.run();//Just run the overridden run() method, not multithreading
    //Syntax format 1: no parameter and no return value
    Runnable r2 = () -> System.out.println("I love Java 8 New features...");
    r2.run();
}


2. Syntax format 2: Lmabda has a parameter and no return value

@Test
public void test02(){
    Consumer<String> consumer = new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println(s);
        }
    };
    consumer.accept("study hard Java programming...");
    //Syntax format 2: Lambda expression has a parameter and no return value
    Consumer<String> consumer1 = (String s) -> { System.out.println(s); };
    consumer1.accept("You can make a lot of money in the future...");
}


3. Syntax format 3: data types can be omitted and can be exited by the compiler, which is called "type inference"

@Test
public void test03(){
    Consumer<String> consumer = new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println(s);
        }
    };
    consumer.accept("study hard Java programming...");
    //Syntax format 3: data types can be omitted and can be exited by the compiler, which is called "type inference"
    Consumer<String> consumer1 = (s) -> { System.out.println(s); };
    consumer1.accept("Eat delicious food every day...");
}


4. Syntax format 4: there is only one parameter, and the parentheses of the parameter can be omitted

@Test
public void test04(){
    Consumer<String> consumer = new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println(s);
        }
    };
    consumer.accept("study hard Java programming...");
    //Syntax format 4: there is only one parameter, and the parentheses of the parameter can be omitted
    Consumer<String> consumer1 = s -> { System.out.println(s); };
    consumer1.accept("Live in a big house in the future...");
}


5. Syntax format 5: Lambda has more than two parameters, multiple execution statements and return values

@Test
public void test05(){
    Comparator<Integer> comparator = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        }
    };
    System.out.println(comparator.compare(25,26));
    System.out.println();
    //Syntax format 5: Lambda has more than two parameters, multiple execution statements and return values
    Comparator<Integer> comparator1 = (Integer o1,Integer o2) -> {System.out.println(o1);
        System.out.println(o2);
        return o1.compareTo(o2);
    };
    System.out.println(comparator1.compare(12,5));
}

6. Syntax format 6: Lambda expression has an execution statement. return and {} if any, can be omitted

@Test
public void test06(){
    Comparator<Integer> comparator = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1.compareTo(o2);
        }
    };
    System.out.println(comparator.compare(25,26));
    System.out.println();
    //Syntax format 6: Lambda expression has an execution statement. return and {} if any, can be omitted
    Comparator<Integer> comparator1 = (Integer o1,Integer o2) -> o1.compareTo(o2);
    System.out.println(comparator1.compare(12,5));
}


Lambda expression summary:
->Left (): parameter types in Lambda's formal parameter list can be omitted (type inference). If there is only one formal parameter, then () can also be omitted
->On the right {}: the Lamdba body is enclosed by a pair of {}. If there is only one execution statement in {}, the parentheses can be omitted, and the return keyword can also be omitted.

2, Functional interface

If only one abstract method is declared in an interface, the interface is called a functional interface.
Lambda expressions, method references, constructor references, and array references are all regarded as instances of functional interfaces.
Use the annotation @ functional interface to identify checks, such as Consumer, Runnable, Comparator, etc.

@Test
public void test01(){
    happyTime(200.0, new Consumer<Double>() {
        @Override
        public void accept(Double aDouble) {
            System.out.println("Flying to Shanghai to buy Nongfu mountain spring cost:"+aDouble);
        }
    });
    System.out.println();
    happyTime(300.0,money -> System.out.println("Flying to Hainan to buy Nongfu mountain spring cost:"+money));
}
public void happyTime(Double money, Consumer<Double> cons){
 cons.accept(money);
}

@Test
public void test02(){
    List<String> list = Arrays.asList("Beijing", "Nanjing", "the Western Capital", "Tokyo", "Tianjin");
    List<String> arrayList = fielterString(list, new Predicate<String>() {
        @Override
        public boolean test(String s) {
            return s.contains("Beijing");
        }
    });
    System.out.println(arrayList.toString());
    List<String> fielterString = fielterString(list, s -> s.contains("Beijing"));
    System.out.println(fielterString.toString());

}
public List<String> fielterString(List<String> list, Predicate<String> pre){
    ArrayList<String> arrayList = new ArrayList<>();
    for(String s : list){
        if(pre.test(s)){
            arrayList.add(s);
        }
    }
    return arrayList;
}

3, Method reference

671
A method reference is a lambda expression. Lambda is an instance of a functional interface, so a method reference is an instance of a functional interface
Requirements for method reference: the parameter list and return value type of the abstract method implementing the interface must be consistent with the parameter list and return value type of the method referenced by the method!
Format: class (or object): method name
There are three main cases of method reference

1. Object: non static method

@Test
public void test01(){
    //1. Functional interfaces are generally used
    Consumer<String> consumer = new Consumer<String>() {
        @Override
        public void accept(String s) {//Void accept in Consumer
            System.out.println(s);
        }
    };
    consumer.accept("Beijing");
    //2.Lambda expression
    Consumer<String> consumer1 = s -> System.out.println(s);
    consumer1.accept("the Western Capital");
    //3. Method reference
    PrintStream ps = System.out;//Out. Println in System
    Consumer<String> consumer2 = ps::println;
    consumer2.accept("Nanjing");
}


2. Class: static method

@Test
public void test02(){
    //1. Functional interfaces are generally used
    Comparator<Integer> comparator = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {//Int compare in Comparator (t T1, t T2)
            return Integer.compare(o1,o2);
        }
    };
    System.out.println(comparator.compare(25, 26));//Output return value - 1
    //2.Lambda expression
    Comparator<Integer> comparator1 = (o1,o2) -> Integer.compare(o1,o2);
    System.out.println(comparator1.compare(35,26));//1
    //3. Method reference
    Comparator<Integer> comparator2 = Integer::compare;//Int compare in Integer (t T1, t T2)
    System.out.println(comparator2.compare(23,52));//-1
}


3. Class: non static method

@Test
public void test03(){
    //1. Functional interfaces are generally used
    Comparator<String> comparator = new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            return o1.compareTo(o2);
        }
    };
    System.out.println(comparator.compare("abs","abc"));
    //2.Lambda expression
    Comparator<String> comparator1 = (s1,s2) -> s1.compareTo(s2);
    System.out.println(comparator1.compare("abc","abd"));//Int compare in Comparator (t T1, t T2)
    //3. Method reference
    Comparator<String> comparator2 = String::compareTo;//int t1.compareTo(t2) in String
    System.out.println(comparator2.compare("abd","abc"));
}

5, Constructor reference

Constructor reference is lambda expression. Lambda is an instance of functional interface, so method reference is also an instance of functional interface
Similar to method references, the formal parameter list of abstract methods of functional interfaces is consistent with that of constructors. The return value type of the abstract method is the type of the class to which the constructor belongs.

/**
 * Constructor reference test class
 * @author wds
 * @date 2021-12-01-10:02
 */
public class ReflectionTest {
    //Constructor reference
    //T get in Supplier
    //Null parameter constructor in Customer: Customer()
    @Test
    public void test01(){
        Supplier<Customer> supplier = new Supplier<Customer>() {
            @Override
            public Customer get() {
                return new Customer();
            }
        };
        System.out.println(supplier.get());
        Supplier<Customer> supplier1 = () -> new Customer();
        System.out.println(supplier1.get());
        Supplier<Customer> supplier2 = Customer::new;
        System.out.println(supplier2.get());
    }
    //R apply in Function (T)
    //Constructor of one parameter in Customer: Customer(int age)
    @Test
    public void test02(){
        Function<Integer,Customer> function = new Function<Integer, Customer>() {
            @Override
            public Customer apply(Integer age) {
                return new Customer(age);
            }
        };
        System.out.println(function.apply(19));
        Function<Integer,Customer> function1 = age -> new Customer(age);
        System.out.println(function1.apply(16));
        Function<Integer,Customer> function2 = Customer::new;
        System.out.println(function2.apply(17));
    }
    //Apply in BiFunction (T, t, U)
    //Constructor of two parameters in Customer: Customer(String name,int age)
    @Test
    public void test03(){
        BiFunction<String,Integer,Customer> biFunction = new BiFunction<String, Integer, Customer>() {
            @Override
            public Customer apply(String name, Integer age) {
                return new Customer(name,age);
            }
        };
        System.out.println(biFunction.apply("Xiao Wang",19));
        BiFunction<String,Integer,Customer> biFunction1 = (name,age) -> new Customer(name,age);
        System.out.println(biFunction1.apply("Xiao LV",17));
        BiFunction<String,Integer,Customer> biFunction2 = Customer::new;
        System.out.println(biFunction2.apply("Xiao Zhang",20));
    }
}
class Customer {
    private String name;
    private int age;
    public Customer() {
    }
    public Customer(int age) {
        this.age = age;
    }
    public Customer(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

test01() test results

test02() test results

test03() test results

6, Array reference

Array reference can be regarded as a special case of constructor reference. In fact, it is to create an array. The first parameter is array length and the second parameter is array data type.

@Test
public void test(){
    //1. General usage of functional interface
    Function<Integer,String[]> function = new Function<Integer, String[]>() {
        @Override
        public String[] apply(Integer length) {
            return new String[length];
        }
    };
    String[] arr = function.apply(5);
    System.out.println(Arrays.toString(arr));
    //2.Lambda expression
    Function<Integer,String[]> function1 = length -> new String[length];
    String[] arr1 = function1.apply(6);
    System.out.println(Arrays.toString(arr1));
    //3. Array reference
    Function<Integer,String[]> function2 = String[] :: new;
    String[] arr2 = function2.apply(7);
    System.out.println(Arrays.toString(arr2));
}

Topics: Java Back-end