一、什么是Lammda 表达式
Lammda 表达式是JAVA8的新特性,匿名内部类的语法糖。
匿名类型最大的问题就在于其冗余的语法。有人戏称匿名类型导致了“高度问题”(height problem),下面的13-18行代码中,只有第16行是实际工作的内容。
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
Function<Integer,String> function1=new Function<Integer,String>() {
@Override
public String apply(Integer s) {
return String.valueOf(s);
}
};
Lambda表达式指的是应用在单一抽象方法(Single Abstract Method,SAM,即函数式接口@FunctionalInterface) 下的一种简化定义形式,可以用来解决匿名内部类的定义复杂问题。
本质上,Lambda表达式是函数式接口实现类的实例化对象。
二、Lammda 表达式的语法形式
(参数) -> 方法体
‘(参数)’对应着函数式接口的抽象方法的形参。
‘方法体’相当于函数式接口的实现类覆写抽象方法的方法体。
Lammda 表达式有以下三种使用形式
方法主体为一个表达式 | (paras)-> expression |
---|---|
方法主体为一行执行代码 | (paras)-> statement |
方法主体需要多行代码 | (paras)-> { statements } |
如果只是只是简单计算并将结果返回,可以省略return,如’ (x,y) -> x+y ;‘。
三、目标类型(Target typing)/类型推断
编译器负责推导lambda表达式的类型。它利用lambda表达式所在上下文所期待的类型进行推导,这个被期待的类型被称为目标类型。
lambda表达式只能出现在目标类型为函数式接口的上下文中。
这就意味着同样的lambda表达式在不同上下文里可以拥有不同的类型:
Callable<String> c = () -> "done";
PrivilegedAction<String> a = () -> "done";
lambda表达式对目标类型也是有要求的。
编译器会检查lambda表达式的类型和目标类型的方法签名(method signature,方法名称和方法参数类型)是否一致。当且仅当下面所有条件均满足时,lambda表达式才可以被赋给目标类型 T :
- T 是一个函数式接口
- lambda表达式的参数和 T 的方法参数在数量和类型上一一对应
- lambda表达式的返回值和 T 的方法返回值相兼容(Compatible)
- lambda表达式内所抛出的异常和 T 的方法 throws 类型相兼容
由此,我们可以简化lambda表达式的声明形式中的参数类型声明。
这和泛型方法调用是非常相似的。
//函数式接口不是应该只有一个方法吗?
//为什么Comparator有两个抽象方法?
//因为boolean equals(Object obj)在Object类中已经有默认实现了(地址比较)。
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
}
Comparator<String> c = (String s1,String s2) -> s1.compareToIgnoreCase(s2);
Comparator<String> c = (s1,s2) -> s1.compareToIgnoreCase(s2);
Map<String, Integer> m1 = new HashMap<>();
Map<Integer, String> m2 = new HashMap<>();