JDK 1.8 新特性 ( 一) ---- Lambda表达式(二)

lambda表达式的冒号用法

  1. 当 ::前面为一个类名,后面跟一个静态方法时,如下所示,此时等号左边的函数式接口中的方法和静态方法签名一致即可,即方法参数个数和类型一致,如果左边的函数式接口中的方法返回值不是void则要求右边lambda静态方法的返回值和其一致,如果左边的函数式接口中的方法返回值是void,则右边的lambda静态方法的返回值可以为任意类型。 (参数个数和类型一致, 返回非void, 一致, 返回void, 任意类型)
public static void main(String[] args) {
     
        Consumer<String> a = Test12::testA; // 只需要传方法名即可
        MyTest1<String> m1 = Test12::testA; // 只需要传方法名即可

        BiConsumer<String, String> b = Test12::testB; // 只需要传方法名即可
        MyTest2<String, String> m2 = Test12::testB; // 只需要传方法名即可
        
        a.accept("a");
        m1.accept("a");
        b.accept("b1", "b2" );
        m2.accept("b1", "b2");
    }

    public static void testA(String a) {
     
        System.out.println(a);
    }

    public static void testB(String a, String b) {
     
        System.out.println(a + b);
    }

    @FunctionalInterface
    private interface MyTest1<T> {
     
        void accept(T a);
    }

    @FunctionalInterface
    private interface MyTest2<T, U> {
     
        void accept(T a, U b);
    }
  1. 当::前面为一个类名,后面为一个实例方法时,如下图所示,此时要求等号左边的函数式接口方法中的第一个参数为实例对象,后面的参数和实例方法保持一致即可。即函数式接口方法的参数个数比实例方法的参数多一个,因为最前面一个留给了实例对象。(接口参数个数比实例方法多一个, 第一个放实例)
public static void main(String[] args) {
     
        Consumer<Test12> a1 = Test12::test1; // 只需要传方法名即可
        BiConsumer<Test12, String> a2 = Test12::test1; // 只需要传方法名即可
        MyFunctionInterface<Test12, String, String> a3 = Test12::test1; // 只需要传方法名即可

        a1.accept(new Test12());
        a2.accept(new Test12(), "a");
        a3.accept(new Test12(),"b1", "b2" );
    }

    public void test1() {
     
        System.out.println("无参数");
    }

    public void test1(String a) {
     
        System.out.println(a);
    }

    public void test1(String a, String b) {
     
        System.out.println(a + b);
    }

    @FunctionalInterface
    private interface MyFunctionInterface<T, U, K> {
     
        void accept(T a, U u, K k);
    }
  1. 当::前面为this时,后面肯定为实例方法,如下图所示,此时等号左边的函数式接口中的方法和实例方法签名一致即可,与上面1中所述的静态方法看上去类似,但是注意这边是在实例方法中声明的。(实例方法中申明, 参数一致)
public class Test12 {
     
    private String str = "a";
    public static void main(String[] args) {
     
        new Test12().test();
    }

    public void test() {
     
        Consumer<String> a1 = this::test1;  // 只需要传方法名即可
        BiConsumer<String, String> a2 = this::test1;  // 只需要传方法名即可
        a1.accept("a");
        a2.accept("a", "b");
    }
    public void test1(String a) {
     
        System.out.println(a + str);
    }

    public void test1(String a, String b) {
     
        System.out.println(a + b + str);
    }
}
  1. lambda省略数据类型或括号
public class Java8Tester {
    public static void main(String args[]){
        Java8Tester tester = new Java8Tester();

        // 类型声明
        MathOperation addition = (int a, int b) -> a + b;

        // 不用类型声明
        MathOperation subtraction = (a, b) -> a - b;

        // 大括号中的返回语句
        MathOperation multiplication = (int a, int b) -> { return a * b; };

        // 没有大括号及返回语句
        MathOperation division = (int a, int b) -> a / b;

        System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
        System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
        System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
        System.out.println("10 / 5 = " + tester.operate(10, 5, division));

        // 不用括号
        GreetingService greetService1 = message ->
                System.out.println("Hello " + message);

        // 用括号
        GreetingService greetService2 = (message) ->
                System.out.println("Hello " + message);

        greetService1.sayMessage("Runoob");
        greetService2.sayMessage("Google");
    }

    interface MathOperation {
        int operation(int a, int b);
    }

    interface GreetingService {
        void sayMessage(String message);
    }

    private int operate(int a, int b, MathOperation mathOperation){
        return mathOperation.operation(a, b);
    }
}

打印lambda类信息

通过在java执行命令后面追加 配置(-Djdk.internal.lambda.dumpProxyClasses) java -Djdk.internal.lambda.dumpProxyClasses com.m.LambdaTest 即可在对应的类下面找到lambda对应的类信息数据, 通过 javap -p -c -v ${lambda} 即可查看类信息里的具体内容

https://blog.csdn.net/jiankunking/article/details/79825928

SerializedLambda

函数式接口是支持序列化的, 通过上面的反编译, 可以看到lambda类中多出了一个 writeReplace 方法
注意函数式接口一定要继承Serializable接口才能获取方法信息

public class Test1212 {
    public static void main(String[] args) throws Exception {
        Func func = Person1::getAge;
        Serializable serializable = func;

//        Serializable serializable1 = Person1::getAge; // 语法错误, 因为编译器校验的时候左边必须是函数接口, 而不会去转换, 实际上按照java的原理, 应该是正确的, 编译器加了控制而已

        System.out.println(serializable);
        Method method = func.getClass().getDeclaredMethod("writeReplace");
        method.setAccessible(Boolean.TRUE);
        SerializedLambda lambda = (SerializedLambda) method.invoke(func);
        System.out.println(lambda.getImplMethodName());
    }
}

@FunctionalInterface
interface Func extends Serializable {
    T get(U u);
}

class Person1 {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

你可能感兴趣的:(JDK,新特性,lambda,冒号用法)