Lambda表达式(Java8新特性)——java学习总结(4)

一、Lambda表达式的产生

Lambda表达式是作为行为参数化的一种优化,以下将会顺序介绍行为参数化,匿名类等概念,再引出Lambda表达式。

1、一等值

若要真正认识行为参数化带来的便利,首先要认识一下一等值

一等值,又称作java的一等公民,即java可以操作的值,可以它的包含关系如下:

一等值
原始值
对象的引用
int类型
double类型
...

java可以操作的值究竟是什么意思呢?狭义上来说,是可以作为参数传递给方法的值。

2、二等值

有了一等值,自然就有二等值,二等值即指
有助于表示值的结构,但在程序执行期间不能传递的结构

通俗意义上来说就是不能作为参数传递的结构,例如类和方法

二等值
方法
..
成员变量1
成员变量2

类内这些成员变量是用于表示值,所以类是一个用于表示值的结构,因为类可以实例化来生产值,同理,方法也是

总结:

能否作为参数传递
不能
一等值
二等值

3、行为参数化

我们如果需要让同一个方法实现不同的需求,我们可以将代码以接口实例的形式作为参数传入,称为行为参数化,这也是将二等值变为一等值的方法。

下面看一个行为参数化的例子:

问题:假如果农需要找出所有的绿苹果;也要找出所有的重量大于150的苹果。

分析:两个需求,都是迭代每一个苹果,再根据判断条件选出每一个符合条件的苹果。

这样,我们先定义一个迭代每一个苹果的方法,参数需要传入苹果集合和判断条件(行为参数化)

public static List<Apple> filter(List<Apple> inventory, ApplePredicate p) {
  List<Apple> result = new ArrayList<>();
  for (Apple apple : inventory) {
    if (p.test(apple)) {
      result.add(apple);
    }
  }
  return result;
}

这样,我们需要定义一个ApplePredicate 接口,其有两个实现类,分别判断绿苹果和重量大于150.

public interface ApplePredicate{
	boolean test (Apple apple);
} 
public class AppleWeightPredicate implements ApplePredicate {
  @Override
  public boolean test(Apple apple) {
    return apple.getWeight() > 150;
  }
}
public class AppleColorPredicate implements ApplePredicate {
  @Override
  public boolean test(Apple apple) {
    return apple.getColor() == Color.GREEN;
  }
}

进行调用

public static void main(String... args) {
//省略苹果集合的创建
List<Apple> heavyApples = filter(inventory, new AppleWeightPredicate());
System.out.println(heavyApples);
}

这样就实现了把判断这个行为作为参数传入去,从而进行各种判断。

在这里插入图片描述

显然,这样的做法是非常笨重的。所以一般不会这样做,我们往往用匿名内部类来解决这些笨重的代码,也就是不需要再额外显式定义实现类。

4、匿名内部类

匿名内部类是行为参数化的一个改进,它不再需要显式实现类,只需对接口方法进行实现即可
下面这个例子是对上面例子的改进:
在调用的时候,匿名内部类定义判断行为

List<Apple> redApples = filter(inventory,new ApplePredicate(){
   public boolean test(Apple a){
       return RED.equals(a.getColor());
   } 
});

但是,这样子看起来还是很复杂,并且一下子还是比较困难看出这是表示什么意思,所以在java8中开发出了Lambda表达式,这里先放上用Lambda的形式,可见其比匿名类简洁了许多

List<Apple> redApples = 
	filter(inventory,(Apple a)-> RED.equals(a.getColor()));

二、Lambda表达式详解

另一个例子:

假如我们需要根据苹果重量进行排序,我们可以调用list.sort(Comparator c)方法,其参数需要是一个Comparator接口,在java8前,我们只能用匿名内部类的方式来定义比较条件。

appleList.sort(new Comparator<Apple>(){
    public int compare(Apple a1,Apple a2){
        return a1.getWeight().compareTo(a2.getWeight());
    }
});

但在Java8后,引入了Lambda表达式,以上的写法可大大简化,如下

appleList.sort(
(Apple a1,Apple a2)-> {a1.getWeight().compareTo(a2.getWeight())}
);

接下来我们会细细分析,但有一点值得注意的是,Lambda表达式是以Comparator实现类的形式作为参数传入的。

1、lambda表达式的结构

  • 参数列表:就是上例的(Apple a1,Apple a2)
  • 箭头: 即 ->
  • Lambda主体,对应上例的{a1.getWeight().compareTo(a2.getWeight())}

Lambda表达式的格式

(i)参数列表
  • 如果参数类型可以通过上下文(目标类型)进行类型推断出,那么参数类型可以省略
    例如
Comparator<Apple> c = (Apple a1,Apple a2) -> {a1.getWeight().compareTo(a2.getWeight())};

这个时候,因为目标类型是Comparator<Apple>,所以在参数列表无须指定参数类型,因为java可以推断得出。如下。

Comparator<Apple> c = (a1,a2) -> {a1.getWeight().compareTo(a2.getWeight())};
  • 参数列表可以为空,主体也可以为空,即如下表达式是成立的
 () -> {}
(ii)Lambda主体
  • 标准上来说,主体是一个代码块,可以包含多条语句
    例:
() -> {
	System.out.println("Hello");
	System.out.println("World");
}
  • Lambda表达式有返回值,且没有其他语句,可省略花括号和return关键字

例:() -> "Hello"等价于() -> {return "Hello";}

2、Lambda表达式的使用详解

(i)函数式接口的引入

(可以先看下面图解,这样好理解一点)
再回到这一章最开始给出的例子,我们想对苹果根据重量进行排序。

appleList.sort(Comparator c)	//Comparator 也是函数式接口

在这个过程中,我们需要进行迭代,在迭代中对每两个苹果进行比较,比较的标杆是什么呢?就是重量,我们需要将比较重量这一行为作为参数传递给sort()。

而sort()怎么知道传进来的参数是什么呢?它就使用了一个接口来当作占位符,这种接口只有一个未实现的方法(默认方法除外),这种接口被称作函数式接口

我们可以联想一下数学上的函数就可以理解它为什么叫函数式接口。

  • 函数式接口只有一个方法,有输入,有输出(空也算作一种输入输出)
    int Comparator<T>(T t1,T t2);
  • 数学上的函数也是,接收输入,然后输出
    y = f( x, X )
  • 找一下对应关系即可知道,y就是int ,t1和t2分别与x和X对应,Comparator自然就与f()对应
  • 而Lambda表达式也可以等同于f(x , X) = x^2 + X^3这种表达式

至于为什么函数式接口只能有一个方法,因为一个接口只能对应一个f(),如果有多个方法,调用f()时,java就不知道究竟要找哪一个方法执行。

下面给出图解(这个图解针对的是选择苹果的例子)
在这里插入图片描述

(ii)函数描述符

函数式接口的抽象方法的签名必须要与Lambda表达式的签名匹配。我们把这种抽象方法的签名叫做函数描述符
所谓签名就是包括参数和返回的一个集合
例如:
函数式接口T Supplier<T>() 的方法签名是() -> T
Lambda表达式() -> "Hello"的签名() -> String

在编译过程中,java编译器会对Lambda表达式的签名进行类型检查,看看是否符合接口方法的签名。

(iii)类型检查流程

这里引用《Java实战》的一篇插图,里面讲解的非常清楚
在这里插入图片描述
注:此文是阅读《Java实战》的学习总结,若希望深入学习,请自行购买《Java实战》学习。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值