lambda表达式是Java8提出的新特性,表示一个可传递的代码块(函数)
lambda表达式
//借助比较器类实现Arrays.sort
public class normal {
public static void main(String[] args) {
String[] array = {"abc", "d", "ef"};
Arrays.sort(array, new LenComparator());
for(String a : array) {
System.out.println(a);
}
}
}
class LenComparator implements Comparator<String>{
public int compare(String first, String second) {
if(first.length() > second.length()) return 1;
else if(first.length() < second.length()) return -1;
else return 0;
}
}
//lambda表达式实现Arrays.sort
public static void main(String[] args) {
String[] array = {"abc", "d", "ef"};
Arrays.sort(array, (String first, String second) -> first.length() - second.length());
for(String a : array) {
System.out.println(a);
}
}
//得到同样结果
d
ef
abc
两者同样是将一段代码传入到sort方法中,在Java中表示一段代码就必须创建一个对象并实例化才能实现传入,这个过程较为复杂也并不直观。而lambda表达式(String first, String second) -> first.length() - second.length()
代替了比较器类,实现了一个代码块简介的表示和传递
lambda表达式基本语法
参数及其类型 + 箭头 + 代码块
- 无参数时仍需(),如果参数类型可由上下文推导则可省略类型,若为单个参数可省去()
- 可以使用单个表达式,也可以用{ }内的代码块,用{}时必须return
- 返回类型可由上下文推导则可省略return,但如果使用return则所有分支必须包含return
像上文例中的Arrays的比较器——Comparator接口,用lambda表达式替换了该接口的一个实现抽象方法的实例,这种接口就是函数式接口
函数式接口
只有一个抽象方法的接口(Comparator中有compare和equal两个抽象方法,但equal属于Object覆盖方法,不会计入接口的抽象方法数量)
//同样的效果不同写法,这里的Comparator就是函数式接口,lambda表达式即可看作是类型为函数式接口的数据
public static void main(String[] args) {
Comparator<String> cp = (first, second) -> first.length() - second.length();
String[] array = {"abc", "d", "ef"};
Arrays.sort(array, cp);
for(String a : array) {
System.out.println(a);
}
}
java提供很多中类型的函数式接口,按照不同参数类型返回类型及特殊方法区分,
详见Java 8 函数式接口。调用函数式接口作为参数,在方法中调用接口中的方法,即可在方法中使用lambda表达式。常见的像list.removeif方法使用Predicate函数式接口,删除满足特定条件的列表成员。也可以编写自己的函数式接口,可以使用@FuncationalInterface注解,静态检查抽象方法个数是否符合规定。
如果lambda表达式中的代码块所要执行的功能,在已有的类方法中已经出现,为了简化代码,可以直接调用该方法,即直接引用方法。
方法引用
当lambda表达式的参数形式与方法参数形式相同时
- object.instanceMethod
- Class.staticMethod
特别的,
- Class.instanceMethod 第一个参数作为方法的目标
//使用方法引用达成同一效果
public class method {
public static void main(String[] args) {
String[] array = {"abc", "d", "ef"};
Arrays.sort(array, length::lengthSort);
for(String a : array) {
System.out.println(a);
}
}
}
class length{
public static int lengthSort(String first, String second) {
return first.length() - second.length();
}
}
ps. Class::new 表示类构造器的引用
lambda表达式中的变量
- 只能引用值,改变值时会报错,可以用方法引用来实现值改变
- 使用的变量必须为最终变量,之后不能再修改的变量,否则报错
- 使用lambda表达式重点在于延迟执行,可能表达式在创建对象已经回收后才执行。但不用担心表达式调用对象中变量消失问题,因为lambda表达式在创建时就把使用到的变量捕获了。
————《Java核心技术》第六章 总结