0
点赞
收藏
分享

微信扫一扫

Lambda表达式(详细介绍)



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();
}

}

Lambda表达式(详细介绍)_lambda


就只有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();
}

}

Lambda表达式(详细介绍)_lambda_02



多了一个内部类的字节码文件



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();
}

}

Lambda表达式(详细介绍)_匿名内部类_03


就只有2个字节码文件,但是大小也变了,demo有2kb,毕竟里面也有lambda表达式的代码



 就这样,lambda表达式就介绍到这里。



附---Lambda表达式的进军:


  •  方法引用
  • 函数式接口
  • Stream流



举报

相关推荐

0 条评论