Lambda表达式(详细介绍)

本文详细介绍了Lambda表达式的基本语法、省略模式以及与匿名内部类的区别。通过实例展示了Lambda如何简化代码,同时强调了Lambda使用的注意事项,包括必须有接口且接口中仅有一个抽象方法。此外,还探讨了Lambda和匿名内部类在实现原理上的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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表达式的进军:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深知她是一场梦

你打不打赏,我都会一直写博客

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值