一、什么是Lammda 表达式

Lammda 表达式是JAVA8的新特性,匿名内部类的语法糖。
匿名类型最大的问题就在于其冗余的语法。有人戏称匿名类型导致了“高度问题”(height problem),下面的13-18行代码中,只有第16行是实际工作的内容。

  1. @FunctionalInterface
  2. public interface Function<T, R> {
  3. /**
  4. * Applies this function to the given argument.
  5. *
  6. * @param t the function argument
  7. * @return the function result
  8. */
  9. R apply(T t);
  10. }
  11. Function<Integer,String> function1=new Function<Integer,String>() {
  12. @Override
  13. public String apply(Integer s) {
  14. return String.valueOf(s);
  15. }
  16. };

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表达式在不同上下文里可以拥有不同的类型

  1. Callable<String> c = () -> "done";
  2. PrivilegedAction<String> a = () -> "done";

lambda表达式对目标类型也是有要求的。
编译器会检查lambda表达式的类型和目标类型的方法签名(method signature,方法名称和方法参数类型)是否一致。当且仅当下面所有条件均满足时,lambda表达式才可以被赋给目标类型 T :

  • T 是一个函数式接口
  • lambda表达式的参数和 T 的方法参数在数量和类型上一一对应
  • lambda表达式的返回值和 T 的方法返回值相兼容(Compatible)
  • lambda表达式内所抛出的异常和 T 的方法 throws 类型相兼容

由此,我们可以简化lambda表达式的声明形式中的参数类型声明
这和泛型方法调用是非常相似的。

  1. //函数式接口不是应该只有一个方法吗?
  2. //为什么Comparator有两个抽象方法?
  3. //因为boolean equals(Object obj)在Object类中已经有默认实现了(地址比较)。
  4. @FunctionalInterface
  5. public interface Comparator<T> {
  6. int compare(T o1, T o2);
  7. boolean equals(Object obj);
  8. }
  9. Comparator<String> c = (String s1,String s2) -> s1.compareToIgnoreCase(s2);
  10. Comparator<String> c = (s1,s2) -> s1.compareToIgnoreCase(s2);
  11. Map<String, Integer> m1 = new HashMap<>();
  12. Map<Integer, String> m2 = new HashMap<>();

四、词法作用域