Lambda表达式支持将代码块作为方法参数、允许使用更简洁的代码来创建只有一个抽象方法的接口(函数式接口)的实例。
-
Lambda表达式由三部分组成:
-
1.形参列表:形参列表允许省略形参类型。如果形参列表中只有一个参数,甚至连括号也可省略。
2.箭头 ->:必须通过英文中画线和大于符号组成。
3.代码块:如果代码块只包含一条语句。Lambda表达式允许省略包裹代码块的花括号。
Lambda表达式的主要作用就是代替匿名内部类的烦琐语法
-
1.Lambda表达式的类型也被成为"目标类型",函数式接口可以包含多个默认方法、类方法,但只能声明一个抽象方法
2.使用Lambda表达式,其目标类型必须是"函数式接口",即接口里只能有一个抽象方法。
3.Lambda表达式只能实现一个方法,因此Lambda表达式只能为函数式接口创建对象。
方法引用与构造器引用
我们知道如果Lambda表达式的代码块只有一条代码,程序就可以省略Lambda表达式中的代码块的花括号。不仅如此,如果Lambda表达式的代码块只有一条代码,还可以在代码块中使用方法引用和构造器引用。(方法引用和构造器引用都需要使用两个英文冒号)
- 引用类方法
定义一个函数式接口:
@FunctionalInterface
interface Conver{
Integer co(String from);
}
正常单元测试:
Conver c1=from->Integer.valueOf(from);
Integer v1=c1.co("52");
System.out.println(v1);
方法引用测试:
Conver c1=Integer::valueOf;
Integer v1=c1.co("52");
System.out.println(v1);
- 引用特定对象的实例方法
正常单元测试:
Conver c2=from->"我是小汉,我爱吃饭".indexOf(from);
Integer v2=c2.co("小汉");
System.out.println(v2);
引用特定对象的实例方法测试:
Conver c2="我是小汉,我爱吃饭"::indexOf;
Integer v2=c2.co("小汉");
System.out.println(v2);
- 引用某类对象的实例方法
定义一个函数式接口:
@FunctionalInterface
interface Conver{
String co(String a,int b,int c);
}
正常单元测试:
Conver c1=(a,b,c)->a.substring(b,c);
String v1=c1.co("我是小汉,我爱吃饭",2,8);
System.out.println(v1);
引用某类对象的实例方法测试:
Conver c1=String::substring;
String v1=c1.co("我是小汉,我爱吃饭",2,8);
System.out.println(v1);
- 引用构造器
定义Person类:
class Person{
private String name;
public Person(String name){
this.name=name;
}
//重写头toString
......
}
定义一个函数式接口:
@FunctionalInterface
interface YT{
Person say(String name);
}
正常单元测试:
YT yt=i->new Person(i);
Person p=yt.say("小汉");
System.out.println(p.toString());
引用构造器测试:
YT yt=Person::new;
Person p=yt.say("小汉");
System.out.println(p.toString());
effectively final
一个非final的局部变量或方法参数,其值在初始化后就从未更改,那么该变量就是effectively final。
Java中局部内部类和匿名内部类访问的局部变量必须由final修饰,以保证内部类和外部类的数据一致。但从Java8开始我们可以不加final修饰符,由系统默认添加,当然这在Java8以前的版本是不允许的,Java将这个功能称为effectively final功能。
总结:规则没有变,lambda表达式和匿名内部类访问的局部变量必须是final的,只是不需要我们显式地声明变量为final,从而节省时间。
lambda表达式和匿名内部类的相同点和区别
-
相同点:
-
- 都可以直接访问"effectively final"的局部变量以及外部类的成员变量(包括实例变量和类变量)。
-
- 创建的对象都可以直接调用从接口中继承的默认方法。
区别:
-
1.匿名内部类可以为任意接口、抽象类、普通类创建实例——不管接口包含多少个抽象方法,只要匿名内部类实现所有的抽象方法即可;但lambda表达式只能为函数式接口创建实例。
2.匿名内部类实现的抽象方法的方法体中允许调用接口中定义的默认方法;但lambda表达式的代码块中不允许调用接口中定义的默认方法。