Java8 Lambda表达式与方法引用

223 阅读4分钟

简介

Lambda表达式方法引用是 Java 8 提供的新特性,开发人员可以通过编写函数式接口,使用Lambda表达式和方法引用实现函数式接口。使得接口像函数一样去使用,从而实现函数式编程

参考资料

  1. Java Lambda表达式表达式 实现原理分析

概念

函数式接口

接口中只有单一且需要实现的方法,就是函数式接口。使用@FunctionalInterface,可以强制约束为函数式接口,在编译时,接口中的未实现方法大于一个,就会编译错误。

/**
 * 单一未实现的方法接口(函数式接口)
 * @FunctionalInterface注解约束接口只能有一个未实现的方法
 */
@FunctionalInterface
interface TestFunctionalInterface{
    int add(int b);
}

Lambda表达式

Lambda表达式(匿名函数),可以在任意地方创建函数式接口的实现

Lambda表达式语法

// b 是接口中add方法的参数,与接口方法参数数量相同,类型可以不指定
// -> 指向实现的方法
// {} 接口的实现方法
TestFunctionalInterface testFunc = (b)->{
    return b+1;
};

//简约写法,
//只有一个参数时,可以不用括号
TestFunctionalInterface testFunc = b -> {
    return b+1; 
};
//只有一个行代码时,可以不用大括号和return关键词
TestFunctionalInterface testFunc = b -> b+1; 

示例代码:

package com.studyjava.Lambda;

public class Java8Lambda表达式 {
    /**
     * 接口中只有单一的方法,使用@FunctionInterface注解后,就成了函数式接口
     */
    interface TestFunctionalInterface{
        int add(int b);
    }

    public static void main(String[] args){
        //单独声明变量
        System.out.println("单独声明变量使用");
        TestFunctionalInterface testFunc = (b)->{
            return b+1;
        };
        int result = testFunc.add(10);
        System.out.println("result=>" + result + "\n");

        //使用在方法参数中
        System.out.println("在方法参数中使用");
        result = addOne((b)->{ return b+1;});
        System.out.println("result=>" + result + "\n");

        //声明变量传递给方法参数使用
        System.out.println("声明变量传递给方法参数使用");
        TestFunctionalInterface testFunc2 = (b)->{
            return b+1;
        };
        result = addOne(testFunc2);
        System.out.println("result=>" + result + "\n");
    }
    public static int addOne(TestFunctionalInterface testFunc){
        return testFunc.add(10)+1;
    }
}

方法引用

方法引用:可以将方法或静态方法做为函数式接口的实现。

方法引用语法:

//函数式接口
interface TestInterface{
    int add(int b);
}

class Java8MethodRef{
    //对象方法
    public int add(int b){
        return b+1;
    }
    //类方法(静态方法)
    public static int staticAdd(int b){
        return b-1;
    }
    public static void main(String args[]){
        //对象方法用作参数[变量名]::方法名
        Java8MethodRef java8MethodRef = new Java8MethodRef();
        TestInterface testInterface = java8MethodRef::add;
        //静态方法用作参数[类名]::方法名
        TestInterface testInterfaceStatic = Java8MethodRef::staticAdd;
    }
}

方法引用使用需注意:

  1. 方法引用只能作用在函数式接口中
  2. 方法的方法名可以与接口的方法不一样
  3. 方法的参数数量、参数类型以及返回值类型要和接口的方法一样

示例代码:

package com.studyjava.Lambda;

public class Java8MethodRef {

    /**
     * 单一未实现的方法接口(函数式接口)
     * @FunctionalInterface注释约束接口只能有一个未实现的方法
     */
    @FunctionalInterface
    interface TestInterface{
        int add(int b);
    }

    /**
     * 对象方法
     */
    public int sub(int b){
        return b+1;
    }

    /**
     * 静态方法
     */
    public static int staticSub(int b){
        return b-1;
    }
    
    public static void main(String[] args) {
        //使用Java8MethodRef对象方法引用
        Java8MethodRef java8MethodRef = new Java8MethodRef();
        useTestInterface(java8MethodRef::sub);
        
        //使用声明接口变量再调用
        TestInterface testInterface = java8MethodRef::sub;
        useTestInterface(testInterface);
        
        //使用静态方法引用
        TestInterface testInterface2 = Java8MethodRef::staticSub;
        useTestInterface(testInterface);
    }

    /**
     * 使用接口方法引用
     * @param testInterface
     */
    public static void useTestInterface(TestInterface testInterface){
        int add = testInterface.add(1);
        System.out.println("useTestInterface==>"+add);
    }
}

总结

  1. Lambda表达式与方法引用只能用在函数式接口上

  2. 函数式接口是为了让方法与接口本身绑定,实现方法就是实现整个接口。让接口像函数一样

    1. 单一方法的接口是函数式接口。使用@FunctionalInterface注解强制约束接口只有一个方法
    2. 函数式编程中,函数作为第一等公民,可以像变量一样创建、赋值、传参
  3. Lambda表达式与方法引用是为了从编程方式上,实现函数式编程

    1. Lambda表达式是为了方便创建函数式接口的实现

    2. 方法引用是为了可以使用与函数式接口方法参数数量、参数类型、返回值类型相同的方法,作为函数式接口的实现。实现函数式接口的赋值

实现原理

Lambda表达式

  1. 在类编译时,会生成一个私有静态方法+一个内部类。
  2. 在内部类中实现了函数式接口,在实现接口的方法中,会调用编译器生成的静态方法。
  3. 在使用Lambda表达式的地方,通过传递内部类实例,来调用函数式接口方法。

详细见参考网址:Java Lambda表达式表达式 实现原理分析

方法引用(推测)

方法引用是使用其它类中的方法。那么只需要给接口实现一个匿名的实现类,并在类的方法里调用被引用的方法即可。代码如下 :

TestInterface testInterface = java8MethodRef::sub;

//运行时的代码
TestInterface testInterface = new TestInterface(){
    public int add(int b){
		return java8MethodRef.sub(b);
    }
}