First, introduction of Lambda expressions

  • Lambda expressions are one of the most important new features in Java8. Instead of an interface implementation with a single abstract function, using Lambda expressions makes the code look cleaner and easier to understand, as opposed to anonymous inner classes. Lambda expressions also enhance the ability to iterate, traverse, and filter data over collections and frames.
  • Lambda expressions can replace an interface implementation that has only one abstract function, and instead of anonymous inner classes, the code looks cleaner and easier to understand
  • Lambda expressions also enhance the ability to iterate, traverse, and filter data over collections and frames
  • Lambdas can greatly reduce code redundancy, while making code more readable than long-winded inner, anonymous classes

For example, previously we used anonymous inner classes to implement code:

        Runnable runnable = new Runnable() {
            @Override
            public void run(a) {
                System.out.println("running1 ....."); }}; runnable.run();Copy the code

Use lambda expressions for more concise code:

        Runnable runnable3 = ()-> System.out.println("running2....");
        runnable3.run();
Copy the code

Lambda expression syntax:

LambdaParameters -> LambdaBody
Copy the code



Args -> expr or (object… Args) -> {functional interface abstraction method implementation logic}

1. The number of () parameters is determined by the number of abstract parameters in the functional interface. If there is only one parameter, () can be omitted

{} and return can be omitted when the expr logic is very simple

Case description:

    public static void main(String[] args) throws Exception {
		Callable<String> c1 = new Callable() {
            @Override
            public String call(a) throws Exception {
                return "muxiaonong"; }}; System.out.println(c1.call()); Callable<String> c2 = ()->{return "muxiaonong2"; }; System.out.println(c2.call());// omit {} and return when the logic is simple
        Callable<String> c3 = ()->"muxiaonong3";
        System.out.println(c3.call());
	}
Copy the code

Second, the characteristics of Lambda expressions

  • Functional programming
  • Parameter types are automatically inferred
  • Small amount of code, concise

Lambda expression cases

List of implementations:

​	    ()->{}
​		()->{System.out.println(1); } ()->System.out.println(1) () - > {return 100; } () - >100() - >null
​		(int x)->{return x+1; } (int x)->x+1
​		(x)->x+1
​		x->x+1
Copy the code

Case 1: Thread implementation:

    public static void main(String[] args) {
        // Anonymous inner class
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                System.out.println("runing1.........."); }});//Lambda expression mode
        new Thread(() -> {System.out.println("runing2....."); }).start(); }Copy the code

Case 2: Collection traversal implementation

    public static void main(String[] args) {
        List<String> list = Arrays.asList("java"."python"."scala"."javascript");

        // Ordinary anonymous inner class
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                returno1.length() - o2.length(); }});/ / Lambda method
        Collections.sort(list,(a,b) -> a.length() - b.length());
        list.forEach(System.out::println);
    }
Copy the code

Application scenarios of Lambda expressions

Important things to say three times: anywhere there is a functional interface * 3

What is a functional interface: The interface of only one abstract method (except the method in the Object class) is a functional interface

5. Practical application of Lambda expressions

5.1 No-parameter entity class simulation

Simulate the database connection layer:

@FunctionalInterface
public interface StudentDao {
    void insert(Student student);
}
Copy the code

Entity class

/ * *@Author mxn
 * @DescriptionStudent Entities *@DateTherefore 2020/11/7 *@Param 
 * @return* * /
public class Student {}Copy the code
 public static void main(String[] args) {
        StudentDao sd1 = new StudentDao() {
            @Override
            public void insert(Student student) {
                System.out.println("Insert student 1"); }}; StudentDao sd2 = (student)->{ System.out.println("student: "+student);
        };

        StudentDao sd3 = (Student student)-> System.out.println("student3:"+student);

        sd1.insert(new Student()); // Output inserts student 1
        sd2.insert(new Student());/ / output
        sd3.insert(new Student());/ / output
    }
Copy the code

5.2 Parameterized entity class simulation

Entity class

/ * *@Author mxn
 * @Description 
 * @Date2020/11/7 *;@Param
 * @return* * /
public class Teacher {}Copy the code

Interface simulation layer

@FunctionalInterface
public interface TeacherDao {
    int get(Teacher teacher);
}
Copy the code

Implementation layer

 public static void main(String[] args) {
        TeacherDao td1 = new TeacherDao() {
            @Override
            public int get(Teacher teacher) {
                return 1; }}; TeacherDao td2 = (teacher)->{return 2; }; TeacherDao td3 = (Teacher teacher)->{return 3; }; TeacherDao td4 = (teacher)->4;
        TeacherDao td5 = (Teacher teacher)->5;

        System.out.println(td1.get(new Teacher()));/ / output 1
        System.out.println(td2.get(new Teacher()));2 / / output
        System.out.println(td3.get(new Teacher()));3 / / output
        System.out.println(td4.get(new Teacher()));/ / output 4
        System.out.println(td5.get(new Teacher()));/ / output 5
}
Copy the code

Functional interfaces

Supplier: represents one output Consumer: represents one input BiConsumer: represents two inputs Function: represents one input and one output (input and output are generally of different types) UnaryOperator: BiFunction: Represents two inputs, one output (input and output are of the same type) BiFunction: Represents two inputs, one output (normally input and output are of different types) BinaryOperator: represents two inputs, one output (input and output are of the same type)

A series of functional interfaces are provided in Java to accept subsequent incoming logic, but with input and output requirements

6.1 Supplier: represents an output

 		Supplier<String> s1 = ()->{return "muxiaonong"; }; Supplier<String> s2 = ()->"muxiaonong2";
        System.out.println(s1.get());/ / output muxiaonong
        System.out.println(s2.get());/ / output muxiaonong2
Copy the code

6.2 Consumer: Represents an input

	    Consumer<String> c11 = (str) -> System.out.println(str);
        c11.accept("beijing");Beijing / / output
Copy the code

6.3 BiConsumer: Indicates two inputs

		BiFunction<String,String,Integer> bf = (a,b)->a.length()+b.length();
        System.out.println(bf.apply("Good luck"."Chicken tonight."));// Outputs a string of length 8
Copy the code

6.4 Function: Represents one input and one output

// Function
      
        receives the implementation of the following Function, specifying that there must be one input (String) and one output (Integer).
      ,integer>
 Function<String,Integer> f1 = (str)->{returnstr.length(); }; System.out.println(f1.apply("abcdefg"));// Output length 7
Copy the code

Seven, the method of reference

  • A method reference is an existing method or constructor used to directly access a class or instance. A method reference provides a way to refer to a method without executing it, and may be used if the implementation of an abstract method happens to be implemented by calling another method

7.1 Classification of method references

type grammar Corresponding lambda expression
Static method reference The name of the class: : staticMethod -> Class name. StaticMethod (args)
Instance method reference inst::instMethod (args) -> inst.instMethod(args)
Object method reference The name of the class: : instMethod (inst,args) -> Class name instMethod(args)
Constructor reference The name of the class: : new (args) -> New class name (args)

7.2 Static Method References

  • Static method references: Use static method references if the implementation of a functional interface happens to be implemented by calling a static method

/ * * *@program: lambda
 * @ClassName Test2
 * @description:
 * @author: muxiaonong
 * @create: "* 2020-10-28@Version1.0 * * /
public class Test2 {
	// Static method with no arguments
	 static String put(a){
	        System.out.println("put.....");
	        return "put";
	    }
	
	// static method with parameters
	public static void getSize(int size){
	        System.out.println(size);
	    }
	
	 // Static method with parameters and return values
	 public static String toUpperCase(String str){
	        return str.toUpperCase();
	    }
	    
	// Two input parameters, one return value static method
    public static Integer getLength(String str,String str2){
        return str.length()+str2.length();
    }
	
	  public static void main(String[] args) {
	    // Static method with no arguments - normal call
		System.out.println(put());/ / output put
		// Static method with no arguments - native call
		Supplier<String> s1 = ()-> Test2.put();
	    System.out.println(s1.get());/ / output put
		// Static method with no arguments - static method reference
		Supplier<String> s2 = Test2::put;
	    System.out.println(s2.get());/ / output put
		// Static method with no arguments - inner class call
	 	Supplier<String> s3 = Fun::hehe;
	    System.out.println(s3.get()); / / output hehe
		
		// Static methods with parameters - static method references
		Consumer<Integer> c1 = Test2::getSize;
	    Consumer<Integer> c2 = (size)-> Test2.getSize(size);
	    c1.accept(123);
	    c2.accept(111);
	
		// Static method with parameters and return values
		Function<String,String> f1 = (str)->str.toUpperCase();
	    Function<String,String> f2 = (str)-> Test2.toUpperCase(str);
	    Function<String,String> f3 = Test2::toUpperCase;
	    Function<String,String> f4 = Test2::toUpperCase;
	
	    System.out.println(f1.apply("abc"));/ / output ABC
	    System.out.println(f2.apply("abc"));/ / output ABC
	    System.out.println(f3.apply("abc"));/ / output ABC
	    System.out.println(f4.apply("abc"));/ / output ABC

		// Two parameters and one return value function interface
 		BiFunction<String,String,Integer> bf = (a, b)->a.length()+b.length();
        BiFunction<String,String,Integer> bf2 = Test2::getLength;
        System.out.println(bf2.apply("abc"."def"));/ / output 6
        System.out.println(bf.apply("abc"."def"));/ / output 6
	
	}

	/ / inner classes
	class Fun {
	    public static String hehe(a){
	        return "hehe";
	    }
	
	    public static String toUpperCase(String str){
	        returnstr.toUpperCase(); }}}Copy the code

7.3 Instance Method Reference

  • Instance method references: Use instance method references if the implementation of a functional interface happens to be implemented by calling an instance method of an instance
public class Test3 {
	// The instance has no parameter method
    public String put(a){
        return "put...";
    }

	// The instance has parameter methods
    public void getSize(int size){
        System.out.println("size:"+size);
    }

	// The instance has parameters and return methods
    public String toUpperCase(String str){
        return  str.toUpperCase();
    }
    public static void main(String[] args) {
    	// Instance method returns with no arguments - normal call
        System.out.println(new Test3().put());/ / output put...
        Supplier<String> s1 = ()->new Test3().put();
        Supplier<String> s2 = ()->{return newTest3().put(); }; Supplier<String> s3 =new Test3()::put;
        System.out.println(s1.get());/ / output put...
        System.out.println(s2.get());/ / output put...
        System.out.println(s3.get());/ / output put...

        // create a unique test3 object
        Test3 test = new Test3();

        Consumer<Integer> c1 = (size)->new Test3().getSize(size);
        Consumer<Integer> c2 = new Test3()::getSize;
        Consumer<Integer> c3 = test::getSize;


        c1.accept(123);/ / output size: 123
        c2.accept(123);/ / output size: 123
        c3.accept(123);/ / output size: 123

        Function<String,String> f1 = (str)->str.toUpperCase();
        Function<String,String> f2 = (str)->test.toUpperCase(str);
        Function<String,String> f3 = new Test3()::toUpperCase;
        Function<String,String> f4 = test::toUpperCase;
        System.out.println(f1.apply("abc"));/ / output ABC
        System.out.println(f2.apply("abc"));/ / output ABC
        System.out.println(f3.apply("abc"));/ / output ABC
        System.out.println(f4.apply("abc"));/ / output ABC}}Copy the code

7.4 Object method References

  • Object method references: The first parameter type of an abstract method happens to be the type of the instance method, and the remaining parameters of the abstract method happen to be the parameters of the instance method. Object method references can be used if the implementation of a functional interface can be implemented by instance method calls described above
/ * *@Author mxn
 * @Description//TODO object method references *@Date 14:26 2020/11/7
 * @Param 
 * @return* * /
public class Test4 {
    public static void main(String[] args) {
        Consumer<Too> c1 = (too)->new Too().foo();
        c1.accept(new Too());/ / output foo

        Consumer<Too> c2 = (Too too) ->new Too2().foo();
        c2.accept(new Too());/ / output foo -- too2

        Consumer<Too> c3 = Too::foo;
        c3.accept(new Too());/ / output foo

        BiConsumer<Too2,String> bc = (too2,str)->new Too2().show(str);
        BiConsumer<Too2,String> bc2 = Too2::show;
        bc.accept(new Too2(),"abc");
        bc2.accept(new Too2(),"def");

        BiFunction<Exec,String,Integer> bf1 = (e,s)->new Exec().test(s);
        bf1.apply(new Exec(),"abc");
        BiFunction<Exec,String,Integer> bf2 = Exec::test;
        bf2.apply(new Exec(),"def"); }}class Exec{
    public int test(String name){
        return 1; }}class Too{
    public Integer fun(String s){
        return 1;
    }
    public void foo(a){
        System.out.println("foo"); }}class Too2{
    public Integer fun(String s){
        return 1;
    }
    public void foo(a){
        System.out.println("foo---too2");
    }

    public void show(String str){
        System.out.println("show ---too2"+str); }}Copy the code

7.5 Constructor reference

  • Constructor references: Use a constructor reference if the implementation of a functional interface happens to be implemented by calling a class constructor
/ * *@Author mxn
 * @Description//TODO constructor references *@Date 14:27 2020/11/7
 * @Param 
 * @return* * /
public class Test5 {
    public static void main(String[] args) {
        Supplier<Person> s1 = ()->new Person();
        s1.get();// Output calls the constructor without arguments
        Supplier<Person> s2 = Person::new;
        s2.get();// Output calls the constructor without arguments

        Supplier<List> s3 = ArrayList::new;
        Supplier<Set> s4 = HashSet::new;
        Supplier<Thread> s5 = Thread::new;
        Supplier<String> s6 = String::new;

        Consumer<Integer> c1 = (age)->new Account(age);
        Consumer<Integer> c2 = Account::new;
        c1.accept(123);// The output age argument constructs 123
        c2.accept(456);// Output the age parameter to construct 456

        Function<String,Account> f1 = (str)->new Account(str);
        Function<String,Account> f2 = Account::new;
        f1.apply("abc");// The output STR argument constructs ABC
        f2.apply("def");// the output STR argument constructs def}}class Account{
    public Account(a){
        System.out.println("Call the no-argument constructor");
    }

    public Account(int age){
        System.out.println("Age parameter construction" +age);
    }

    public Account(String str){
        System.out.println("STR parameter construction"+str); }}class Person{
    public Person(a){
        System.out.println("Call constructor with no arguments"); }}Copy the code

Eight, summary

  • The introduction of Lambda expressions in JAVA 8 embraces the idea of a functional programming language, which emphasizes the computation of functions over the execution of instructions in contrast to instruction programming.
  • Lambda expressions can make code looks simple, but to some extent, increased the readability of the code and the complexity of the debugging, so when use should be used as far as possible is team are familiar with, or simply don’t use, or to maintain is a painful thing, the small knowledge here today, there is a problem of friends may leave a message below, and you come on!