作为一只小测试,在每次测试之前总会或多或少的把开发的代码拉下来本地review,在看代码过程中发现很多“小箭头”表达式,代码不再像之前一样“臃肿”,显得简洁了很多。
了解了以后知道,这些“小箭头”运用到了lambda表达式,那么什么是lambda表达式呢?为什么它能这么简洁?它与匿名内部类之间的区别是啥呢?
什么是lambda表达式?
通过百度百科可以看到,Lambda 表达式(lambda expression)是一个匿名函数,即没有函数名的函数,它把函数作为基本运算单元,函数可以作为变量,可以接收函数,还可以返回函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),他们必须依附于一类特别的对象类型——函数式接口(functional interface)。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。
其实在Scala等jvm语言中lambda早就被广泛运用了,像我们平常经常使用的Python、Java 8、C#、C++ 11都已经引入lambda表达式,使用它设计的代码会更加简洁易读。当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口。
lambda表达式语法结构:
Lambda表达式通常使用(param)->(body)语法书写,基本格式如下:
//没有参数
() -> body
// 1个参数
(param) -> body
// 1个参数
(param) ->{ body; }
// 多个参数
(param1, param2...) -> { body }
// 多个参数
(type1 param1, type2 param2...) -> { body }
举一个简单list遍历的🌰:
1.普通循环遍历表达式
public void function(){
String [] stringArray={"hello","world"};
for(int i=0;i<stringArray.length;i++){
System.out.println(stringArray[i]);
}
}
2.lambda表达式
public void function(){
//List遍历
List<String> books = new ArrayList<String>(3);
books.add("TEST1");
books.add("TEST2");
books.add("TEST3");
books.forEach(obj -> System.out.println("测试:" + obj));
books.forEach(System.out::println);
//map的遍历
Map maps = new HashMap();
maps.put(1, "test1");
maps.put(2, "test2");
maps.forEach((k, v) -> System.out.println("Key : " + k + " Value : " + v));
}
}
观察到lambda表达式的格式是:
(obj) -> {
return System.out.println("测试:" + obj);
}
如果只有一行retrun的代码,就可以是这样:
obj -> System.out.println("测试:" + obj)
其中,参数是(a,b),参数类型可以省略,因为编译器可以自动推断出object类型,这得益于javac的类型推断机制,编译器能够根据上下文信息推断出参数的类型,当然也有推断失败的时候,这时就需要手动指明参数类型了。注意,Java是强类型语言,每个变量和对象都必需有明确的类型。-> { ... }表示方法体,所有代码写在内部即可。
为什么它能这么简洁?
Lambda表达式没有class定义,因此写法非常简洁。
它与匿名内部类之间的区别是啥呢?
在了解区别之前先知道一下什么是匿名内部类,这种类顾名思义,没有名字(当然只是程序员不用指定类名,但是编译器会自动为该类取名的),创建方法如下:
new 父类构造器(参数列表)|实现接口()
{
//匿名内部类的类体部分
}
那么两者之间有啥区别呢?从两个方面解释,1.编译方法 2.关键词this的使用
1.编译方法不同
匿名类编译后会生成两个class文件,分别是主类跟内部类产生。是会额外消耗class文件的
而lambda表达式编译结果只有一个class,不会产生class额外消耗。
还可以通过查看字节码的方式去看两者内部不同,lambda表达式通过java7中新加的invokedynamic 指令动态绑定私有函数方法从而做到了不会产生新的类。
2.关键字this的使用
因为lambda表达式跟内部类如此不同所以this的使用也不是代表内部对象了,而是跟外部一样。这也是两者之间的区别。
总结:
lambda表达式的结构是:
-
Lambda表达式可以有0个参数或者多个参数。
-
参数类型可以显式声明,也可以让javac编译器从上下文自动推断类型。
-
多个参数用小括号括起来,逗号分隔。(a,b)-> a+b
-
没有参数用空括号表示。()->1
-
Lambda表达式的正文可以包含0条,一条或多条语句,如果有返回值则必须包含返回值语句。如果只有一条可省略大括号。
虽然lambda表达式很简洁效率也高,但是缺点也是很明显哒,非并行计算情况下,其计算速度没有比传统的 for 循环快;不容易进行调试等等。有他的好也会有弊端,切记勿滥用。