[Java from the beginning to the end] No11.JDK1.8 Functional Programming Lambda

1 Overview

  • The concept of functional programming was proposed in JDK 1.8, and the most disruptive way of writing code is undoubtedly Lambda:

The requirements for using Lambda expressions are also relatively simple.
1. Functional implementation first requires an interface . 2. Secondly, there is only one abstract method
in the interface. Lambda is similar to the anonymous inner class mode. The abstract method in the interface has been A functional implementation is similar to the implementation of an anonymous inner class, so it does not allow multiple abstract methods in the interface, otherwise it will not be able to determine which method is implemented.

For example:
Lambda is used here to implement the run() method of the Runable interface.

public class View01 {
    
    

    public static void main(String[] args) {
    
    
        new Thread( () -> {
    
    
            System.out.println("体验 lambdaλ");
        }).start();
    }

}

2. Getting started

  • The standard usage format of Lambda is:

() -> {}
The parentheses are the placement position of the parameters, and the curly braces are the writing position of the method body
. This is a simple method to implement.

  • Usage examples:
/**
 * 抽象方法无参无返回值
 */
public interface Interface1 {
    
    

    void method();

}

/**
 * 抽象方法带参无返回值
 */
public interface Interface2 {
    
    

    void method(String str);

}

/**
 * 抽象方法带参带返回值
 */
public interface Interface3 {
    
    

    String method(String name, int age);

}

/**
 * Lambda
 */
public class Lambda_Pratice_Test1 {
    
    

    public static void main(String[] args) {
    
    

        // Lambda表达式练习(抽象方法无参无返回值)
        test1(() -> {
    
    
            System.out.println("test1");
        });

        // Lambda表达式练习(抽象方法带参无返回值)
        test2((String s) -> {
    
    
            System.out.println(s);
        }, "test2");

        // Lambda表达式练习(抽象方法带参带返回值)
        String result = test3((String name, int age) -> {
    
    
            return name + age;
        }, "chenfeilin ", 24);
        System.out.println(result);

    }

    private static void test1(Interface1 interface1) {
    
    
        interface1.method();
    }

    private static void test2(Interface2 interface2, String str) {
    
    
        interface2.method(str);
    }

    private static String test3(Interface3 interface3, String name, int age) {
    
    
        String result = interface3.method(name, age);
        return result;
    }

}

3. Omit patterns and precautions

/**
 * Lambda表达式的省略模式
 * Lambda表达式的注意事项
 */
public class Lambda_Pratice_Test2 {
    
    

    public static void main(String[] args) {
    
    

        // Lambda表达式的省略模式
        /**
         * 可推导的就是可省略的
         * 参数类型可以省略,如果参数只有一个,圆括号可省略
         * 如果方法体只有一句,花括号,结尾分号可省略,return关键字也可以省略,如果有的话
         */
        test2(s -> System.out.println(s), "test2");
        test3((name, age) -> name + age, "test3", 24);

        // Lambda表达式的注意事项
        /**
         * lambda的使用需要依赖上下文环境,也就是不能随便写
         * 最常用的就是作为参数或者返回值
         * 以及作为局部变量赋值
         */
         
		// 直接这么写是不行的
		// () -> {System.out.println("this is interface1 method");}
		
        Interface1 interface1 = () -> {
    
    
            System.out.println("this is interface1 method");
        };
        interface1.method();

    }
    
    private static void test2(Interface2 interface2, String str) {
    
    
        interface2.method(str);
    }

    private static String test3(Interface3 interface3, String name, int age) {
    
    
        String result = interface3.method(name, age);
        return result;
    }

}

4.The difference between Lambda expressions and anonymous inner classes

/**
 * Lambda 和 匿名内部类的区别
 */
public class Lambda_Test {
    
    

    public static void main(String[] args) {
    
    

        // 区别1:使用类型场景的不同
        // 匿名内部类:接口,抽象类,具体类都可以
//        useInterface(new Itface() {
    
    
//            @Override
//            public void method() {
    
    
//                System.out.println("useInterface");
//            }
//        });
//
//        useAbstract(new AbstractClass() {
    
    
//            @Override
//            public void method() {
    
    
//                System.out.println("useAbstract");
//            }
//        });
//
//        useTrueClass(new TrueClass() {
    
    
//            @Override
//            public void method() {
    
    
//                System.out.println("useTrueClass");
//            }
//        });

        // lambda:只有接口可以,抽象类和具体类不行
//        useInterface(() -> System.out.println("useInterface"));
        // Target type of a lambda conversion must be an interface
        // useAbstract(() -> System.out.println("aaa"));
        // useTrueClass(() -> System.out.println("aaa"));

        // ------------------------------------------------------------------------------

        // 区别2:使用局限性不同
        // 在接口中有多个抽象方法时,是无法使用lambda的,但是匿名内部类可以

        useInterface(new Itface() {
    
    
            @Override
            public void method() {
    
    
                System.out.println("m1");
            }

            @Override
            public void method2() {
    
    
                System.out.println("m2");
            }
        });

        // 区别3:在具体的代码实现上
        // 匿名内部类会生成一个单独class文件
        // 而lambda不会,他的匿名类文件是动态生成的

    }

    public static void useInterface(Itface itface){
    
    
        itface.method();
    }

    public static void useAbstract(AbstractClass abstractClass) {
    
    
        abstractClass.method();
    }

    public static void useTrueClass(TrueClass trueClass) {
    
    
        trueClass.method();
    }

}

public abstract class AbstractClass {
    
    

    public abstract void method();

}

public interface Itface {
    
    

    public void method();

    public void method2();

}

public class TrueClass {
    
    

    public void method(){
    
    

    }

}

5.Method quote::

When using Lambda expressions, the code we actually pass in is a solution: to operate on parameters,
consider a situation: if the operation plan we specify in Lambda already has the same plan, then Is it still necessary to write repeated logic?
The answer is definitely not necessary.
So how do we use existing solutions?
This is the method reference we are going to explain. We use existing solutions through method references.

The method reference symbol consists of two colons. The left side is usually the class name or object instance, and the right side is usually the method name. Note that no parameters are written.
For example:
student::study

Code example:

public interface PrintAble {
    
    
    void print(String s);
}

public class Test_method {
    
    

    public static void main(String[] args) {
    
    
		
		// 完整版写法
        method((String s) -> {
    
    
            System.out.println("77777777777");
        });
		
		// 省略后写法
        method(s -> System.out.println("77777777777"));

		// 方法引用
        method(System.out::println);

   }

    public static void method(PrintAble printAble) {
    
    
        printAble.print("sss");
    }

}

  • Reference class method (static method)
public interface StringToInt {
    
    

    public int to(String s);

}

public class Method_test {
    
    

    public static void main(String[] args) {
    
    

        // 就是普通的静态方法调用
        ttt(Integer::parseInt);

    }

    public static void ttt(StringToInt sti) {
    
    
        int to = sti.to("666");
        System.out.println(to);
    }

}

  • Instance method of reference object
public interface MakeStringUp {
    
    

    public String upString(String small);

}

public class Stringhelper {
    
    

    public String Up(String s) {
    
    
        System.out.println("快快变大!");
        return s.toUpperCase();
    }

}

public class Test_class {
    
    

    public static void main(String[] args) {
    
    

        Stringhelper sh = new Stringhelper();
        StringToUp(sh::Up);

    }

    private static void StringToUp(MakeStringUp msu) {
    
    
        String hello_small = msu.upString("hello small");
        System.out.println(hello_small);
    }

}

  • Reference class instance method
public class MethodClass {
    
    

    private String name;
    private int age;

    public MethodClass() {
    
    
    }

    public MethodClass(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public void setField(String str) {
    
    
        String name = str.split(",")[0];
        int age = Integer.parseInt(str.split(",")[1]);
        this.name = name;
        this.age = age;
        System.out.println(name);
        System.out.println(age);
    }

    public static void staticMethod(String str) {
    
    
        System.out.println(str);
    }

    public void normalMethod(String str) {
    
    
        System.out.println(str);
    }

    @Override
    public String toString() {
    
    
        return "MethodClass{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public interface GetMethodClass {
    
    

    MethodClass getMethodClass(String name, int age);

}

public class FFYY_Test1 {
    
    

    public static void main(String[] args) {
    
    

        // 引用类的实例方法
        // 这个类的实例方法名字就很抽象,使用类名,去引用普通方法,一般我们是使用类的实例才能去调用其普通成员方法的。

        /**
         * 此时
         * 接口方法的参数为: (MethodClass methodClass, String str)
         * 我们想要引用的方法的参数为: setField(String str)
         * 我们想要引用的类的实例为 MethodClass
         *
         * 这里虽然参数匹配不上 (MethodClass methodClass, String str) != (String str)
         * 但是这里是可以使用的,并且调用的时候为 类名::普通方法名
         * 这里是没有使用类的实例来做方法调用的,而这个普通方法又必须要类的实例才能调用,因为不是静态方法
         * 什么时候可以这么写呢,在接口的参数中包含了这个类的实例的时候,这么写默认就是这个方法参数类实例调用了这个普通方法
         * 这里this的赋值也是成功了的
         */
        System.out.println("-----------------");
        MethodClass m = new MethodClass();
        System.out.println(m);
        test5(MethodClass::setField, m);
        System.out.println(m);

    }

    private static void test5(InterfaceTest interfaceTest, MethodClass methodClass) {
    
    
        interfaceTest.interfaceMethod(methodClass , "cfl,24");
    }

}

  • reference constructor
public interface StudentBuilder {
    
    

    Student getSb(String name, int age);

}

public class Student {
    
    

    private String name = "";
    private int age = 0;

    public Student() {
    
    
    }

    public Student(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 boolean equals(Object o) {
    
    
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
    
    
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
    
    
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

/**
 * 方法引用之引用构造方法
 * 其实也是引用普通类的方法,不过是构造方法,用了new关键字而已,大可以理解为引用了一个带参数和返回值的普通方法
 */
public class ConstructTest {
    
    

    public static void main(String[] args) {
    
    

        // 方法引用
        getStudent(Student::new);

    }

    private static void getStudent(StudentBuilder studentBuilder) {
    
    
        System.out.println(studentBuilder.getSb("陈菲林", 777));
    }

}

Guess you like

Origin blog.csdn.net/cjl836735455/article/details/108697167