Lambda表达式,实际上就是函数式编程
我们先用一个例子体验一下lambda表达式
- Programmer:程序员接口,里面有一个编码的抽象方法
 - Me:我的类,实现了程序员接口
 - Demo:测试Demo,里面有useProgrammer(Programmer p)方法,方法内部调用接口的writeCode()方法,主方法分别用实现类、匿名内部类、lambda表达式3中方式调用useProgrammer方法。
 
Programmer接口的代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-10:49
 */
public interface Programmer {
    void writeCode();
}Me类的代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-10:51
 */
public class Me implements Programmer {
    @Override
    public void writeCode() {
        System.out.println("整天加班写代码!");
    }
}测试Demo的代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-10:54
 */
public class Demo {
    public static void main(String[] args) {
        //实现类
        Programmer p = new Me();
        useProgrammer(p);
        //匿名内部类
        useProgrammer(new Programmer() {
            @Override
            public void writeCode() {
                System.out.println("需求永远在改变!");
            }
        });
        // lambda表达式
        useProgrammer(()->{
            System.out.println("加班永无止尽!");
        });
    }
    private static void useProgrammer(Programmer p){
        p.writeCode();
    }
}运行测试Demo,输出结果
整天加班写代码!
 需求永远在改变!
 加班永无止尽!
Lambda表达式的语法:
(parameters) -> expression 或 (parameters) ->{ statements; }
- 格式:(行驶参数)->{代码块}
 - 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
 - ->:由英文画线和大于符号组成,固定写法。代表指向动作
 - 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
 
下面就针对lambda表达式中,是否有参数,是否有返回值做一个代码实例
- Interface1:接口1,无参无返回值方法mathod()
 - Interface2:接口2,有参无返回值方法mathod()
 - Interface3:接口3,有参有返回值方法mathod()
 - Demo2:测试Demo2,主方法针对以上3中情况做示例
 
Interface1:接口1代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-11:40
 */
public interface Interface1 {
    void mathod();
}Interface2:接口2代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-11:40
 */
public interface Interface2 {
    void mathod(String s);
}Interface3:接口3代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-11:40
 */
public interface Interface3 {
    int mathod(int a ,int b);
}测试Demo2代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-10:54
 */
public class Demo2 {
    public static void main(String[] args) {
        // 无参无返回值
        useInterface1(()->{
            System.out.println("无参无返回值");
        });
        // 有参无返回值
        useInterface2((String s)->{
            System.out.println(s);
        });
        // 有参有返回值
        useInterface3((int a,int b)->{
            return a+b;
        });
    }
    private static void useInterface1(Interface1 i){
        i.mathod();
    }
    private static void useInterface2(Interface2 i){
        i.mathod("有参无返回值");
    }
    private static void useInterface3(Interface3 i){
        int mathod = i.mathod(3, 5);
        System.out.println("有参有返回值"+mathod);
    }
}运行测试Demo2,输出:
无参无返回值
 有参无返回值
 有参有返回值8
有没有觉得lambda是不是很简洁,接着往下看,还有更简洁的方式,下面我们就来看看
Lambda表达式的省略模式
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
 - 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
 - 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
 - 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
 
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-10:54
 */
public class Demo3 {
    public static void main(String[] args) {
        // 参数类型可以省略,并且要么都不省,要么全部省
        useInterface3(( a, b)->{
            return a+b;
        });
        // 如果参数有且仅有一个,那么小括号()可以省略
        useInterface2(s->{
            System.out.println(s);
        });
        // 如果代码块的语句只有一条,那么大括号{}和分号;也可以省略
        useInterface1(()-> System.out.println("无惨无返回值"));
        useInterface2(s-> System.out.println(s));
        // 如果代码块的语句只有一条,那么大括号{}和分号;也可以省略,如果有return,那么return也要省略掉
        //useInterface3((int a,int b)-> return a+b);//报错,因为省略大括号{}和分号;,没有省略return
        useInterface3((int a,int b)->  a+b);
    }
    private static void useInterface1(Interface1 i){
        i.mathod();
    }
    private static void useInterface2(Interface2 i){
        i.mathod("有参无返回值");
    }
    private static void useInterface3(Interface3 i){
        int mathod = i.mathod(3, 5);
        System.out.println("有参有返回值"+mathod);
    }
}Lambda表达式的注意事项
- 使用Lambda必须要有接口,并且要求接口中有且仅有一个抽象方法
 - 必须有上下文环境,才能推导出Lambda对应的接口
 
- Interface1:接口1,无参无返回值方法mathod()
 - Interface4:接口4,没有抽象方法
 - Interface2:接口2,有参无返回值方法mathod()
 - Interface5:接口5,有参无返回值方法mathod()
 - TalkLove:接口TalkLove,有参无返回值方法eat()和see()
 - Demo3:测试Demo3,主方法针对Lambda的注意事项进行示例,并且Lambda不可以的,用匿名内部类实现
 
Interface1:接口1代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-11:40
 */
public interface Interface1 {
    void mathod();
}Interface4:接口4代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-11:40
 */
public interface Interface4 {
    public static void mathod(){
        System.out.println("接口可以有静态方法");
    }
}Interface2:接口2代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-11:40
 */
public interface Interface2 {
    void mathod(String s);
}Interface5:接口5代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-11:40
 */
public interface Interface5 {
    void mathod(String s);
}TalkLove:接口TalkLove代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-10:13
 */
public interface TalkLove {
    void eat();
    void see();
}Demo3:测试Demo3代码
package com.testLambda;
/**
 * @author 林高禄
 * @create 2020-06-02-10:54
 */
public class Demo4 {
    public static void main(String[] args) {
        // 成功
        Interface1 i = ()->{};
        useInterface1(i);
        useInterface1(()->{});
        // 报错,No target method found,接口没有抽象方法
        //useInterface4(()->{});
        useInterface4(new Interface4() {
        });
        // 报错,Ambiguous method call. Both,方法调用不明确。两者
        //useInterface2((s -> System.out.println(s)));
        useInterface2(new Interface2() {
            @Override
            public void mathod(String s) {
                System.out.println(s);
            }
        });
        useInterface2(new Interface5() {
            @Override
            public void mathod(String s) {
                System.out.println(s);
            }
        });
        // 报错,Multiple non-overriding abstract methods found in interface com.testLambda.TalkLove,在接口中找到多个非重写的抽象方法
        //useTalkLove(()->{});
        useTalkLove(new TalkLove() {
            @Override
            public void eat() {
                System.out.println("谈恋爱--吃饭");
            }
            @Override
            public void see() {
                System.out.println("谈恋爱--看电影");
            }
        });
    }
    private static void useInterface1(Interface1 i){
    }
    private static void useInterface4(Interface4 i){
    }
    private static void useTalkLove(TalkLove t){
        t.eat();
        t.see();
    }
    private static void useInterface2(Interface2 i){
        i.mathod("有参无返回值");
    }
    private static void useInterface2(Interface5 i){
    }
}运行测试demo3,输出:
谈恋爱--吃饭
 谈恋爱--看电影
 有参无返回值
Lambda表达式和匿名内部类的区别
由以上的测试,我们知道Lambda表达式不能处理的,匿名内部类都可以处理,但是2者还是有一些区别的
所需类型不同
- 匿名内部类:可以是接口,也可以是抽象类,也可以是具体类
 - Lambda表达式:只能是接口
 
使用限制不同
- 如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
 - 如果接口中国多余一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
 
实现原理不同
- 匿名内部类:编译之后,产生一个单独的.class字节码文件
 - Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候自动生成
 
类型不同和限制不同上面都表明,下面我们主要讲实现原理不同
- Programmer:程序员接口,里面有一个编码的抽象方法
 - Demo:测试Demo,里面有useProgrammer(Programmer p)方法,方法内部调用接口的writeCode()方法,主方法分别用匿名内部类、lambda表达式2中方式调用useProgrammer方法,展现实现原理不同。
 
Programmer:程序员接口代码
package com.testLambda2;
/**
 * @author 林高禄
 * @create 2020-06-02-10:49
 */
public interface Programmer {
    void writeCode();
}Demo:测试Demo代码,主方法什么都没有,不运行
package com.testLambda2;
/**
 * @author 林高禄
 * @create 2020-06-02-10:54
 */
public class Demo {
    public static void main(String[] args) {
    }
    private static void useProgrammer(Programmer p){
        p.writeCode();
    }
}
就只有2个字节码文件
Demo:测试Demo代码,主方法用匿名内部类,不运行
package com.testLambda2;
/**
 * @author 林高禄
 * @create 2020-06-02-10:54
 */
public class Demo {
    public static void main(String[] args) {
        //匿名内部类
        useProgrammer(new Programmer() {
            @Override
            public void writeCode() {
                System.out.println("需求永远在改变!");
            }
        });
    }
    private static void useProgrammer(Programmer p){
        p.writeCode();
    }
}
多了一个内部类的字节码文件
Demo:测试Demo代码,主方法用Lambda表达式,不运行
package com.testLambda2;
/**
 * @author 林高禄
 * @create 2020-06-02-10:54
 */
public class Demo {
    public static void main(String[] args) {
        // lambda表达式
        useProgrammer(()->{
            System.out.println("加班永无止尽!");
        });
    }
    private static void useProgrammer(Programmer p){
        p.writeCode();
    }
}
就只有2个字节码文件,但是大小也变了,demo有2kb,毕竟里面也有lambda表达式的代码
就这样,lambda表达式就介绍到这里。
附---Lambda表达式的进军:
- 方法引用
 - 函数式接口
 - Stream流
 










