概念
lambda表达式是java8的新特性之一,本质上来说是一个匿名函数,可以简化接口的实现从而简化代码。
使用限定:只有函数式接口才能使用lambda表达式简化实现。
- 函数式接口:接口中只有一个需要实现的方法的接口就是函数式接口(不包括default修饰的默认的方法,static修饰的静态方法,以及从object继承的toString等方法。)
- 可以使用
@FunctionalInterface
注解检验是否是函数式接口
在写lambda表达式的时候只用关注参数列表和方法体:
(参数)->{方法体}
其中:
- 参数部分︰方法的参数列表,要求和实现的接口中的方法参数部分一致,包括参数的数量和类型。
- 方法体部分︰方法的实现部分,如果接口中定义的方法有返回值,则在实现的时候,注意返回值的返回。
- ->:分隔参数部分和方法体部分。
精简策略:
精简表达式
可以省略表达式的参数类型
- 如果接口方法参数只有一个,可以省略lambda表达式的小括号。
如:
//函数接口
public interface MyTest{
void test(int a);
}
//lambda表达式
MyTest myTest = a->{System.out.println(a);};
//调用方法
myTest.test();
- 如果接口方法方法体只有一个语句,可以省略大括号。
//函数接口
public interface MyTest{
void test(int a);
}
//lambda表达式
MyTest myTest = a->System.out.println(a);
//调用方法
myTest.test(a);
- 如果接口方法方法体有返回值,则lambda表达式中要有返回值。
//函数接口
public interface MyTest{
//有返回值的方法
int test(int a);
}
***********************************************************
//lambda表达式
MyTest myTest = a->{
System.out.println(a);
return a;
};
***********************************************************
//调用方法
myTest.test(a);
- 如果接口方法方法体只有一个语句,并且有返回值,则省略大括号的同时需要把return也省略,否则错误。
//函数接口
public interface MyTest{
int test(int a);
}
***********************************************************
//lambda表达式
MyTest myTest = a->a*a; //等价于a->{return a*a;};
***********************************************************
//调用方法
myTest.test(a);
函数引用:
为了继续简化太过复杂的逻辑的代码,可以调用其他地方已经实现的方法来实现函数接口,这种方式称为函数引用。存在以下情况:
- 静态方法引用:类::静态方法,方法名后不要添加小括号,并且方法的参数和返回值必须和接口的一样
//某个类,其中存在静态方法
public class Demo{
//静态方法
public static void out(){
System.out.println("这是静态方法");
}
}
***********************************************************
//函数式接口
public interface MyTest{
void testMethod();
}
***********************************************************
//使用lambda表达式
MyTest myTest = Demo::out; //等价于 ()->{Demo.out();}
***********************************************************
//调用方法
myTest.testMethod();
- 非静态方法引用:对象::非静态方法名,如果对象没有实例化就要new一个对象,即new 对象::方法名
//某个类,其中存在静态方法
public class Demo{
//非静态方法
public void out(){
System.out.println("这是静态方法");
}
}
***********************************************************
//函数式接口
public interface MyTest{
void testMethod();
}
***********************************************************
//使用lambda表达式
MyTest myTest = new Demo()::out; //等价于 ()->{Demo.out();}
***********************************************************
//调用方法
myTest.testMethod();
- 构造方法的引用:类名::new,无论无参、有参构造方法,都是用这个方式,使用时会自动匹配构造方法,并且可以通过接口中的方法的参数,区分引用的构造方法。(某个接口定义的方法仅仅是为了得到一个类的对象,就可以使用这种方法)
//带三种构造方法的Person类
private static class Person {
String name;
int age;
public Person() {
System.out.println("Person类的无参构造方法执行了");
}
public Person(String name) {
this.name = name;
System.out.println("Person类的有参构造方法执行了");
}
public Person(String name,int age) {
this.name = name;
this.age = age;
System.out.println("Person类的两个参数的构造方法执行中);
}
**********************************************************
//无参构造函数式接口
public interface MyTest1{
Person getNullParameter();
}
//一个参数构造函数式接口
public interface MyTest2{
Person getSingleParameter(String name);
}
//两个参数构造函数式接口
public interface MyTest3{
Person getDoubleParameter(String name,int age);
}
***********************************************************
//使用lambda表达式
//无参
MyTest1 myTest1 = Person::new;
//一个参数
MyTest1 myTest1 = Person::new;
//两个参数
MyTest1 myTest1 = Person::new;
//调用接口的方法
//无参
myTest1.getNullParameter();
//一个参数
myTest2.getSingleParameter("myName");
//两个参数
myTest3.getDoubleParameter("myName",19);
- 对象方法的特殊引用:如果在使用lambda表达式,实现某些接口的时候。lambda表达式中包含了某一个对象,此时方法体中,直接使用这个对象调用它的某一个方法就可以完成整体的逻辑。其他的参数,可以作为调用对象的方法的参数。此时,可以对这种实现进行简化。表达式:对象名::方法名,然后利用接口.方法(参数)即可。
如:
//某个对象的类
public class Person {
private String name ;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
//函数式接口
public interface MyTest{
String get(Person person);
}
//使用lambda表达式
Person person = new Person(); //创建一个person对象
person.setName("zhangsan");
MyTest myTest = Person::getName; //等价于 MyTest myTest = (p)->{p.getName;};
注:lambda表达式中如果用到局部变量,则该局部变量会自动变为常量,不能在后面再做修改,如果是全局变量则没有问题