当前很多公司的java开发环境都升级到jdk8以上了。lambda表达式是java8中最重要的更新,其目的是为了配合随着并行运算流行起来的所谓“函数式”编程改进而来的语法糖。既然是语法糖,那么其实不用这些lambda表达式也是可以实现原有功能的,只不过看起来代码行数多一些而已。
简单说一下对lambda表达式的理解:lambda表达式其实就是“内部匿名类”对象的特定方法的实现代码。这个内部匿名类实现了某个特定接口(由注解@FunctionalInterface标注的)。这个带@FunctionalInterface注解的接口只能有一个方法(否则就不知道lambda表达式要干什么事了)--严格来说是只能有一个抽象方法,因为现在允许接口里有默认实现了,带默认实现那些不算。还是用代码描述更清楚:
假定一个接口定义:
@FunctionalInterface
public interface LamDemo {
int operation(int a,int b);
}
如果不加@FunctionalInterface注解,那么就是一个普通接口,加上了里面的(抽象)方法就只能有一个。上面例子是一个名为operation的方法,两个整数参数,返回值也是整数。
最普通的用法,就是写一个类实现这个接口,然后用的时候创建这个类的对象:
//普通非匿名类实现接口LamDemo
class TempClass implements LamDemo{
@Override
public int operation(int a, int b) {
return a+b;
}
}
用的时候:
//普通对象,常规用法
private LamDemo ldTemp = new TempClass();
匿名类就为了省一点事,不去定义这个TempClass,直接用接口创建对象:
//创建匿名类对象赋予接口类型的变量
private LamDemo _ld = new LamDemo(){
@Override
public int operation(int a, int b) {
return a+b;
}
};
效果等同。
用lambda表达式更进一步,连new这个操作也隐含了:
//在变量中使用lambda表达式
private LamDemo ld=(int a ,int b)-> a+b;
隐含的意思是创建了一个对象,这个对象的类实现了LamDemo接口定义的方法,实现代码是a+b。这样就明白为啥接口只能有一个方法了,否则编译器不知道对应哪个。实现代码的规则是这样的()->{},左边是方法参数,右边是方法体。这是标准写法,但为啥感觉看到的lambda表达式五花八门似的。这就涉及各种各样的所谓“简化规则”。按标准写法上面的例子其实应该写成这样:
//在变量中使用lambda表达式
private LamDemo ld=(int a ,int b)->{return a+b;};
简化规则如下:
参数可以是零个或多个,零个时左边就是一个空()
参数类型可指定,也可省略(因为接口方法定义里已经说了参数类型了)
参数包含在圆括号中,用逗号分隔,一个参数时可省略()
表达式主体可以是零条或多条语句,包含在花括号中,只有一条语句时可省略{}
表达式主体有一条以上语句时,表达式的返回类型与代码块的返回类型一致
表达式只有一条语句时,表达式的返回类型与该语句的返回类型一致
总之就是能犯懒就犯懒,少敲几个字母是几个字母,代价就是初学看起来有点晕。
既然lambda表达式实际上是个匿名对象,那么它就可以赋给变量(上面例子);
可以当作参数传给方法:
//lambda表达式作为方法参数
System.out.println(t.lambdaReturn1(3,5,(a,b)->a*b));
还可以用作方法返回值:
//在返回值中应用lambda expression
public LamDemo lambdaReturn2(){
return (int a,int b)->a*b;
}
完整示例代码:
//普通非匿名类实现接口LamDemo
class TempClass implements LamDemo{
@Override
public int operation(int a, int b) {
return a+b;
}
}
public class Test {
//普通类对象
private LamDemo ldTemp = new TempClass();
//匿名类对象
private LamDemo _ld = new LamDemo(){
@Override
public int operation(int a, int b) {
return a+b;
}
};
//在变量中使用lambda表达式
private LamDemo ld=(int a ,int b)->a+b;
//在参数中使用lambda表达式(见后面调用)
public int lambdaReturn1(int source,int target,LamDemo lr){
return lr.operation(source, target);
}
//在返回值中应用lambda expression
public LamDemo lambdaReturn2(){
return (int a,int b)->a*b;
}
//省略参数类型定义
private LamDemo ld1=(a ,b)-> a+b;
public static void main(String[] args){
Test t=new Test();
System.out.println(t.ld.operation(3, 5));
System.out.println(t.ld1.operation(6, 6));
//lambda表达式作为方法参数
System.out.println(t.lambdaReturn1(3,5,(a,b)->a*b));
//方法返回值是个lambda表达式(是个对象)
System.out.println(t.lambdaReturn2().operation(5,7));
//lambda表达式方式创建新线程并运行(lambda expression作为实现Runnable接口的对象传给Thread的构造函数,其对应唯一方法是void run(),无参数无返回值)
new Thread(()->System.out.println("lambda expression thread run")).start();
/*
* 总结:lambda表达式就是把一段代码作为内部类的对象的某个特定实现(编译器所推导出的函数接口)
* lambda expression实际上是用内部类实现的,所以传过来的参数默认是final的,不可修改
* lambda表达式与匿名内部类的区别在于this标识符:在匿名内部类中使用this指的是此内部类;
* 而在lambda表达式中的this标识符指的是外部调用者
*/
}
}