New JDK feature -- lambda

1.lambda expression

1. Format:
(parameter type parameter name) - >{
Method body;
    Return return value;
}

2. Omission rules
Parameter types in parentheses can be omitted.
If there is only one parameter in parentheses, you can omit parentheses.
If there is only one statement in braces, you can omit the braces, the return keyword and the statement semicolon at the same time.
eg:
new Thread(() ->{
            System.out.println("Lambda expression executed");
        }).start();
Method body:
It can be an expression or a code block. It is the implementation of a method in a functional interface
If the code responsible for the operation cannot be expressed in an expression, it can be implemented using the writing method
However, you must surround it with {} and explicitly use the return statement as needed

2. Functional interface classification  

a. System and definition function interface (Comparator, Runnable)

b. User defined function interface (annotation is required, expression is implemented directly through parameter list, and there can only be one valid method)

@FunctionalInterface
public interface MyInterface {
    String info(String tip);
}

  3. Publicly defined functional interfaces

a. Functional interface: function < T, R >

There are input parameters and return values

Is an abstraction of a method that receives a T-type parameter and returns an R-type result

Execute the content by calling the apply method

Requirement: given a string, return the string length

 

package org.xxxx.demo01;
 
import java.util.function.Function;
 
public class Demo01 {
	public static void main(String[] args) {
		// Define string
		String str = "helloworld";
		
		// Call method
		// Write the method body when calling. The method is more flexible
		int length = testFun(str, (s) -> s.length());
		
		System.out.println(length);
	}
	
	// method
	/**
	 * 
	 * @param str input parameter 
	 * @param fun The expression String is the input type and Integer is the output type
	 * @return Return string length
	 */
	public static int testFun(String str, Function<String, Integer> fun) {
		// implement
		Integer length = fun.apply(str);
		return length;
	}
}

b. Consumer interface: consumer < T >

There are input parameters and no return value
 The corresponding method type is to receive a parameter and has no return value
 Generally speaking Consumer Interfaces are often accompanied by some desired state changes
 Or the occurrence of events, typical forEach It's used Consumer Interface
 Although there is no return value, the result is output to the console
Consumer use accept Perform behavior on parameters

package org.xxxx.demo01;
 
import java.util.function.Consumer;
 
public class Demo01 {
	public static void main(String[] args) {
		// Create string
		String str = "hello world";
		
		// call
		testCon(str, (s) -> System.out.println(s));
	}
	
	/**
	 * 
	 * @param str Incoming parameters
	 * @param con
	 */
	public static void testCon(String str, Consumer<String> con) {
		// implement
		con.accept(str);
	}
}

c. Supply interface: supplier < T >

No incoming parameters, return value

The method type corresponding to the interface does not accept parameters, but provides a return value

use get()Method to get the return value

package org.xxxx.demo01;
 
import java.util.function.Supplier;
 
public class Demo01 {
	public static void main(String[] args) {
		// Create string
		String str = "hello world";
		
		// call
		String sup = testSup(() -> str);
		
		System.out.println(sup);
	}
	
	/**
	 * 
	 * @param sup
	 * @return
	 */
	public static String testSup(Supplier<String> sup) {
		// implement
		String s = sup.get();
		return s;
	}
	
}

d. Assertion interface: predicate < T >

There are incoming parameters and return values Boolean

The method corresponding to this interface is to receive a parameter and return a Boolean Type value

It is mostly used for judgment and filtering test()Method to perform this behavior

Requirement: enter a string to judge whether the length is greater than 0


package org.xxxx.demo01;
 
import java.util.function.Predicate;
 
public class Demo01 {
	public static void main(String[] args) {
		// Create string
		String str = "hello world";
		
		// call
		boolean flag = testPre(str, (s) -> s.length() > 0);
		
		System.out.println(flag);
	}
	
	/**
	 * 
	 * @param str
	 * @param pre
	 * @return
	 */
	public static boolean testPre(String str, Predicate<String> pre) {
		// implement
		boolean flag = pre.test(str);
		
		return flag;
	}
	
}

3. Comparison between lambda and anonymous inner classes

1.Different types are required

     Anonymous internal class, the required type can make class, abstract class and interface;

     Lambda Expression, the required type must be interface.

2.The number of abstract methods is different

     The number of abstract methods in the interface required by the anonymous inner class is arbitrary;

     Lambda The interface required by an expression can only have one abstract method.

3.Different implementation principles

     Anonymous inner class will form an additional class name after compilation $0 of.class file

     Lambda Expressions are generated dynamically when the program is running .class file

4. Examples

public class CollectionsLambdaDemo{
 
    public static void main(String[] args) {
        List<Person> persons = new ArrayList<>();
        persons.add(new Person("Lau Andy",58,174));
        persons.add(new Person("Xue You Zhang",56,176));
        persons.add(new Person("Guo Fucheng",54,171));
        persons.add(new Person("dawn",53,178));
 
        //1. Anonymous inner class to sort the collection
        Collections.sort(persons, new Comparator<Person>() {
            //Age descending sort
            @Override
            public int compare(Person o1, Person o2) {
                return o2.getAge() - o1.getAge();
            }
        });
 
        for (Person person: persons) {
            System.out.println(person);
        }
 
        System.out.println("-----------------------------------");
 
        //2.Lambda expression
        Collections.sort(persons,(Person o1,Person o2) ->{
            return o1.getAge() - o2.getAge();
        });
 
         for (Person person: persons) {
             System.out.println(person);
         }
    }
}
 
//Test results:
    Person{name='Lau Andy', age=58, height=174}
    Person{name='Xue You Zhang', age=56, height=176}
    Person{name='Guo Fucheng', age=54, height=171}
    Person{name='dawn', age=53, height=178}
    -----------------------------------
    Person{name='dawn', age=53, height=178}
    Person{name='Guo Fucheng', age=54, height=171}
    Person{name='Xue You Zhang', age=56, height=176}
    Person{name='Lau Andy', age=58, height=174}

5. Method reference

5.1 format

Symbolic representation: Double colon (:)

Symbol description: the double colon is the method reference operator, and the expression in which it is located is called the method reference.

Application scenario: if the scheme to be implemented by Lambda already has the same scheme in other methods, you can use method reference.

  5.2 common reference methods

Method references can be used flexibly in JDK8 in the following forms:

  1.instanceName::methodName     Object name:: method name

  2.ClassName::staticMethodName     Class name:: static method name

  3.ClassName::methodName     Class name:: method name

  4.ClassName::new     Class name:: New   

  5.TypeName[ ]::new     Array type:: New   (String[]::new)

  5.2.1 object name: method name

public class InstanceName_methodName_demo {
 
    public static void main(String[] args) {
        Date now = new Date();
 
        //Lambda common writing method (calling method)
        Supplier<Long> supplier1 = ()->{
            return now.getTime();
        };
        Long aLong = supplier1.get();
        System.out.println("Common writing:"+aLong);
 
        //Lamdba method reference (object name:: member method name)
        Supplier<Long> supplier2 = now::getTime;
        Long bLong = supplier2.get();
        System.out.println("Method reference writing:"+bLong);
 
        //Use method references to modify Time
        Consumer<Long> consumer = now::setTime;
        consumer.accept(100000000000L);
        Supplier<Long> supplier = now::getTime;
        Long aLong1 = supplier.get();
        System.out.println("Modified Time:"+aLong1);
 
    }
}

   matters needing attention:

The parameters of the referenced method should be the same as those of the abstract method in the interface;(Namely: getTime() The method has no parameters, Supplier Interface abstract method get()Methods also have no parameters)
When an interface abstract method has a return value, the referenced method must also have a return value.      

5.2.2. Class name: static method name

 Because in java.lang.System Static method already exists in class currentTimeMillis(),
 So when we need to pass Lambda Expression to call the method, you can use a method reference.
 By class name::Called as a static method name
 
 public class className_abstractMethodName_demo {
 
    public static void main(String[] args) {
 
        //Lambda common writing method (class name. Static method name)
        Supplier<Long> supplier1 = ()->{
            return System.currentTimeMillis();
        };
 
        Long aLong = supplier1.get();
        System.out.println("Normal call:"+aLong);
 
        //Lambda method reference
        Supplier<Long> supplier2 = System::currentTimeMillis;
        Long bLong = supplier2.get();
        System.out.println("Method reference:"+bLong);
    }
}
 

5.2.3 class name: method name

     stay Java In object-oriented, class names can only call static methods. Class names are used here::The method name has a premise. In fact, it takes the first parameter as the caller of the method. You will understand it by looking at the following code.
     
     public class className_methodName_demo {
 
    public static void main(String[] args) {
        
        //Lambda expression (called as object. Method name)
        Function<String,Integer> fn1 = (String str)->{
            return str.length();
        };
        Integer aLength = fn1.apply("hello world");
        System.out.println("Character length is:"+aLength);
        
        //Lambda expression (called by method reference [class name: method name])
        Function<String,Integer> fn2 = String::length;
        Integer bLength = fn2 .apply("hello world"); 
        System.out.println("Character length is:"+bLength);
 
    }
}

5.2.4 examples

/**
 * TODO Example: step by step analysis of user-defined methods (from complex to simple)
 *      Analyze step by step from 1.Lambda expression -- > 2. Object name:: method name -- > 3. Class name:: method name
 *
 * @author liuzebiao
 * @Date 2020-1-6 15:38
 */
public class Demo01 {
    
    //Array summation method
    public int getSum(int[] arr){
        int sum = 0;
        for(int n : arr){
            sum += n;
        }
        return sum;
    }
 
    public static void main(String[] args) {
        //Customize an array summation method getSum(). This example uses the method reference method of [class name: method name form]
        //Analysis: call getSum() method, pass in an int [] type parameter and return an Integer value. Here, the function < int [], Integer > functional interface is used
 
        //Steps:
        //1. This method is obviously OK, but Lambda expressions are redundant
        Demo01 demo = new Demo01();
        Function<int[],Integer> f1 = (int[] arr)->{
            return demo.getSum(arr);
        };
 
        //2. We can use method reference demo::getSum; [object name:: method name]
        Function<int[],Integer> f2 = demo::getSum;
 
        //3. The object name:: member method is used in the above 2. How to use the [class name:: method name] method for the method written by yourself
        // Analysis: the BiFunction functional interface is needed at this time. BiFunction is similar to the Function functional interface
        // The difference lies in the number of parameters: BiFunction passes 2 parameters and Function passes 1 parameter
 
        // Why do I need to pass two parameters?
        // Through the analysis of the picture just now: 2 = 1.3 method. It can be understood here as the format of [Integer =Demo01.getSum(int []])
        // Therefore, if you use [class name: method name], the first parameter must be the current class name, and the rest are the passed parameters and return parameter types
        // If two parameters are used for analysis and [class name: method name] is used, three parameters need to be passed. JDK8 helps us provide BiFunction/BiConsumer/BiPredicate
 
        BiFunction<Demo01, int[], Integer> f3 = Demo01::getSum;
        int[] arr = {11, 22, 33, 44, 55};
        // Here, when calling the apply() method to pass parameters, you have to pass an instance of the current class (new Demo01() new instance / Demo01.class.newInstance() reflection, etc.)
        // Obviously, it's better to directly use the [object name:: method name] in 2 above. So [class name: method name] is rarely used
        // Therefore, BiFunction/BiConsumer/BiPredicate are rarely used
        Integer sum = f3.apply(new Demo01(), arr);
        System.out.println(sum);
    }
}

5.2.5 class name:: new (constructor reference)

Premise of use:

       The constructor parameter list should be consistent with the parameter list of the abstract method in the interface!
/**
 * TODO person Entity class
 *
 * @author liuzebiao
 * @Date 2020-1-7 15:47
 */
public class Person {
 
    private String  name;
 
    private int age;
 
    public Person() {
        System.out.println("Execute parameterless construction method");
    }
 
    public Person(String name, int age) {
        System.out.println("Execute parametric construction method,name:"+name+";age:"+age);
        this.name = name;
        this.age = age;
    }
 
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


/**
 * TODO Constructor introduction Demo
 *
 * @author liuzebiao
 * @Date 2020-1-7 15:49
 */
public class className_new_constructor {
 
    public static void main(String[] args) {
 
        //1. Use the object parameterless constructor to create a Person object
        //1.1 using Lambda expressions
        Supplier<Person> sup1 = ()->{
            return new Person();
        };
        Person person1 = sup1.get();
        System.out.println(person1);
 
        //1.2 use method reference [class name: new (constructor)]
        Supplier<Person> sup2 = Person::new;
        Person person2 = sup2.get();
        System.out.println(person2);
 
        //2. Create a Person object using the object parameter constructor
        //In this case, the BiFunction functional interface will be used (the first two parameters correspond to the constructor parameter type, and the third parameter is the return value type)
        //2.1 using Lambda expressions
        BiFunction<String,Integer,Person> bif1 = (String name,Integer age)->{
            return new Person(name,age);
        };
        Person person3 = bif1.apply("Mary", 18);
        System.out.println(person3);
 
        //2.2 use method reference [class name: new (constructor)]
        BiFunction<String,Integer,Person> bif2 = Person::new;
        Person person4 = bif2.apply("Mary", 18);   //It determines which constructor to call based on the parameters passed in by the apply() method
        System.out.println(person4);
    }
}

5.2.6. Array type:: new (array import)

/**
 * TODO Array reference creates an array
 *
 * @author liuzebiao
 * @Date 2020-1-7 16:39
 */
public class array_new_demo {
 
    public static void main(String[] args) {
        
        //1. Use Lambda expression to create an int array with length of 10
        Function<Integer,int[]> fn1 = (Integer num)->{
            return new int[num];
        };
        int[] arr1 = fn1.apply(10);
        System.out.println(Arrays.toString(arr1));
 
        //2. Use the array reference method to create an int array with a length of 10
        Function<Integer,int[]> fn2 = int[]::new;
        int[] arr2 = fn2.apply(10);
        System.out.println(Arrays.toString(arr2));
    }
}

Reference source: JDK8 assisted learning (I): analysis of Lambda expression principle_ The blog of the youth carrying sacks - CSDN blog

Tags: Java Lambda Back-end

Posted on Sat, 04 Dec 2021 19:54:48 -0500 by priya_cks