目录
1.Lambda表达式简介
1.1什么是Lambda表达式
Lambda表达式是JDK8针对接口实现类提供的一种更为精简的写法,从而达到简化代码的目的。下面展示Lambda表达式一个最简单的应用,遍历集合时我们可以用for循环遍历:
用Lambda表达式改写:
根据IDEA提示再次进行简化:
笔者第一次看的时候是很懵,这是个啥,C++?别急,看完本篇博文相信小伙伴们都会体验到Lambda表达式的魅力。
1.2 Lambda表达式对接口的要求
虽然Lambda表达式可以简化接口的实现,但并不是对所有的接口都适用,因为其毕竟只是一个匿名方法,当实现的接口中方法数量大于1(无法在一个方法体内实现两个方法)或者小于1(方法都没,该去实现谁呢)的时候无法进行简化,所以Lambda表达式只能实现函数式接口。
2.Lambda表达式语法
2.1 Lambda表达式基础语法
格式:(参数) -> { 方法体 }
->:Lambda操作符,分隔参数部分和方法体
参数:Lambda参数列表(接口中抽象方法形参列表)
方法体:Lambda体(重写的抽象方法的方法体)
2.2 Lambda表达式的使用(6种情况)
语法格式一:无参,无返回值
语法格式二:一个参数,无返回值
语法格式三:数据类型可以省略,可由编译器推断得出,称为"类型推断"
语法格式四:Lambda若只有一个参数时,参数的小括号可以省略
语法格式五:Lambda需要两个或以上的参数时小括号不能省略
语法格式六:当Lambda体只有一条语句时,return和大括号都可以省略
3.Lambda表达式中的函数引用
3.1 函数引用
函数引用:引用一个已经存在的方法,使其代替Lambda表达式完成接口的实现。 Lambda表达式是为了简化接口实现的。在Lambda表达式中不应该出现比较复杂的逻辑。如果Lambda表达式中需要处理的逻辑比较复杂,一般会单独写一个方法,需要的时候直接引用这个方法即可。Demo:
@FunctionalInterface
private static interface Calculate {
int calculate(int a, int b);
}
private static int calculate(int x, int y) {
if (x > y) {
return x - y;
} else if (x < y) {
return y - x;
}
return x + y;
}
public static void main(String[] args) {
Calculate calculate1 = (x, y) -> calculate(x, y);
System.out.println(calculate1.calculate(10,20));
}
3.2 静态方法引用
语法:类::静态方法
注意事项:引用方法的后面不需要添加小括号,引用方法的参数数量、参数类型和返回值类型必须要和接口中定义的一致。
public class FunctionInterfaceDemo {
@FunctionalInterface
private static interface Calculate {
int calculate(int a, int b);
}
private static int calculate(int x, int y) {
if (x > y) {
return x - y;
} else if (x < y) {
return y - x;
}
return x + y;
}
public static void main(String[] args) {
Calculate calculate1 = (x, y) -> calculate(x, y);
System.out.println(calculate1.calculate(10,20));
//上述代码可改为以下静态方法引用
Calculate calculate2 = FunctionInterfaceDemo::calculate;
System.out.println(calculate2.calculate(10,20));
}
}
3.3 非静态方法引用
语法:对象::非静态方法
注意事项:引用方法的后面不需要添加小括号,引用方法的参数数量、参数类型和返回值类型必须要和接口中定义的一致。
public class FunctionInterfaceDemo {
@FunctionalInterface
private interface Calculate {
int calculate(int a, int b);
}
private int calculate(int x, int y) {
if (x > y) {
return x - y;
} else if (x < y) {
return y - x;
}
return x + y;
}
public static void main(String[] args) {
Calculate calculate1 = new FunctionInterfaceDemo()::calculate;
System.out.println(calculate1.calculate(10,20));
}
}
3.4 构造方法引用
语法:类名::new
注意事项:可通过接口中方法的参数区分不同的构造方法。
public class FunctionInterfaceDemo {
private static class Person {
String name;
public Person() {
System.out.println("无参构造被执行了");
}
public Person(String name) {
this.name = name;
System.out.println("有参构造被执行了 name = " + name);
}
}
private static interface GetPersonWithNoneParameter{
Person getPerson();
}
private static interface GetPersonWithSingleParameter {
Person getPerson(String name);
}
public static void main(String[] args) {
//使用Lambda表达式实现无参构造GetPersonWithNoneParameter接口
GetPersonWithNoneParameter getPerson1 = () -> new Person();
//使用Lambda表达式简化上述接口实现
GetPersonWithNoneParameter getPerson2 = Person::new;
//使用Lambda表达式实现有参构造GetPersonWithSingleParameter接口
GetPersonWithSingleParameter getPerson3 = (x) -> new Person();
//使用Lambda表达式简化上述接口实现
GetPersonWithSingleParameter getPerson4 = Person::new;
}
}
3.5 对象方法特殊引用
对象方法特殊引用:如果在使用Lambda表达式实现某些接口时,表达式中包含了某一个对象,此时方法体中直接使用这个对象调用它的某一个方法就可以实现整体的逻辑,其他的参数可作为调用方法的参数,此时可以对这种实现方式进行简化。Demo:
public class FunctionInterfaceDemo {
private static class Person {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@FunctionalInterface
private interface GetName {
String getName(Person person);
}
public static void main(String[] args) {
Person person = new Person();
person.setName("Tom");
//使用Lambda表达式实现无参构造GetPersonWithNoneParameter接口
GetName getName1 = (x) -> x.getName();
System.out.println(getName1.getName(person));
//上述可以简化为
GetName getName2 = Person::getName;
System.out.println(getName2.getName(person));
}
}
重点看简化后的Lambda表达式Person::getName,看起来和3.3非静态方法引用很相似,但仔细看也有不同,非静态方法语法为:类实例::非静态方法,而在这里直接使用的是类名(Person)。我们看着简化后的代码再读一下对象方法特殊引用的定义,表达式中包含了某一个对象x,并且方法体中直接使用x调用其getName()就可以实现整体的逻辑,那么此时(x) -> x.getName()就可以简化为Person::getName。同理setName Demo:
public class FunctionInterfaceDemo {
private static class Person {
String name;
public void setName(String name) {
this.name = name;
}
}
@FunctionalInterface
private interface SetName {
void setName(Person person,String name);
}
public static void main(String[] args) {
Person person = new Person();
SetName setName1 = (x,n) -> x.setName(n);
setName1.setName(person,"Tom");
//上述可以简化为
SetName setName2 = Person::setName;
setName2.setName(person,"Tom");
}
}
表达式中包含了某一个对象x,并且方法体中直接使用x调用其setName()就可以实现整体的逻辑,同时其他的参数n可作为方法调用的参数,那么(x,n) -> x.setName(n)即可简写成Person::setName。
4.使用Lambda表达式需要注意的一个问题
这其实是一个局部内部类的问题,如果某一个局部变量应用在某一个代码段中,那么就形成了对这个局部变量的闭包,这时此局部变量即使没有用final修饰,它默认也是final,既不能发生值的改变。