Lambda表达式的类型检查、类型推断及其带来的限制

前面的文章中我们有提到,Lambda表达式是函数式接口的一个实例,然而,我们并没有从Lambda表达式中看到有关函数式接口的任何信息,因而有必要弄清楚,Lambda的类型是什么?它实现了哪个函数式接口?

类型检查

其实,Lambda表达式的类型是从上下文推断出来的,这里的上下文包括如下3种:

  • 赋值上下文
  • 方法调用上下文(参数与返回值)
  • 类型转换上下文

通过这3种上下文就可以推断出Lambda表达式的目标类型(与之对应的函数式接口)。

下面来看几个示例:

  • 示例1
     
    1. List<Apple> heavierThan150g = filter(inventory, (Apple a) -> a.getWeight() > 150);
    通过方法filter(List< Apple > inventory, Predicate< Apple > p)的调用推断出Lambda表达式(Apple a) -> a.getWeight() > 15的目标类型是Predicate< Apple >,这里,p的抽象方法test接受apple,返回布尔值,与lambda表达式的函数描述符Apple -> boolean相匹配,因此代码的类型检查无误。
  • 示例2:
     
    1. Comparator<Apple> c1 = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
    上面代码是通过赋值上下文推断出Lambda表达式的目录类型。

类型推断

类型推断是指不需要指定lambda表达式参数的类型,它可以从lambda目标类型中推断出来,使我们的lambda表达式更为简洁。

下面代码中,参数a就没有显式的指定其类型为Apple,它可以从上下文中推断而来。

 
  1. List<Apple> greenApples = filter(inventory, a -> "green".equals(a.getColor()));

在Lambda表达式中使用局部变量的一些限制

在Lambda表达式中,也可以使用局部变量,就像匿名内部类在使用局部变量时需要用final修饰一样,Lambda表达式也有这个限制。像下面的代码(错误代码):

 
  1. int portNumber = 1337;
  2. Runnable r = () -> System.out.println(portNumber);
  3. portNumber = 31337;

错误原因:Lambda表达式引用的局部变量必须是final变量或事实上的final变量,这里portNumber被再次修改了,显示不是final类型。

为什么会有这个限制?

局部变量保存在栈上,如果Lambda是在一个子线程中使用局部变量,则使用Lambda的线程,可能会在分配该变量的主线程将这个变量收回之后,去访问该变量。因此,Java在访问自由局部变量时,实际上是在访问它的副本,而不是访问原始变量。如果局部变量是final类型,仅仅赋值一次,那就无所谓了,因此就有了这个限制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值