死磕Lambda表达式(一):初识Lambda

简介: Lambda表达式是表示可传递匿名函数的一种简洁方式,Lambda表达式没有名称,但是有参数列表、函数主体、返回类型,还可能有一个可以抛出的异常列表。它是Java8新增的特性,有了它我
弱小和无知不是生存的障碍,傲慢才是。——《三体》

什么是Lambda表达式

Lambda表达式是表示可传递匿名函数的一种简洁方式,Lambda表达式没有名称,但是有参数列表、函数主体、返回类型,还可能有一个可以抛出的异常列表。它是Java8新增的特性,有了它我们再也不用像之前那样写一堆笨重的匿名类代码了,我们先来体验一下。

与匿名函数对比

下面我们先举个例子,有这样一个表示口罩的类:

package one.more.study;

/**
 * 口罩
 */
public class Mask {
    /**
     * 品牌
     */
    private String brand;
    /**
     * 类型
     */
    private String type;

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

再创建一个口罩列表,添加一些口罩对象:

List<Mask> maskList = new ArrayList<>();
maskList.add(new Mask("3M", "KN95"));
maskList.add(new Mask("3M", "FFP2"));
maskList.add(new Mask("Honeywell", "KN95"));
maskList.add(new Mask("Honeywell", "N95"));

现在我们按照品牌给这个口罩列表进行排序。在Java8之前,我们可以用匿名函数进行实现:

maskList.sort(new Comparator<Mask>() {
    @Override
    public int compare(Mask o1, Mask o2) {
        return o1.getBrand().compareTo(o2.getBrand());
    }
});

我们再使用Lambda表达式实现一下:

maskList.sort((Mask o1, Mask o2) -> o1.getBrand().compareTo(o2.getBrand()));

显而易见,使用Lambda表达式以后,代码看起来更清晰更简洁了。假如你还是一脸懵圈的话也没关系,这里我只是想显摆一下Lambda表达式很牛掰,接下来我会一点点地详细讲解清楚。

Lambda表达式的组成

Lambda表达式由三部分组成,以上面的口罩排序的例子为例,如下图:

  1. 参数列表:本例中是两个Mask对象的参数,采用的是Comparator接口中compare方法的参数。
  2. 箭头->把参数列表和主体分隔为两个部分。
  3. 主体:本例中是把比较口罩品牌的表达式作为Lambda表达式的返回。主体可以修改成另外一种写法,含义是一样的:
maskList.sort((Mask o1, Mask o2) -> {
    return o1.getBrand().compareTo(o2.getBrand());
});

Lambda表达式的基本语法

从上面的例子中的两个种写法中,可以看出Lambda表达式有两种基本语法,分别如下:

  1. (参数列表) -> 表达式
  2. (参数列表) -> { 多条语句 }

只看这两条干瘪的语法,理解起来比较困难,实践出真知,我们来多举几个例子。

Lambda表达式示例

  1. 我们提到的例子,Lambda表达式的参数列表有两个Mask类型的参数,主体是比较两个Mask对象的品牌,返回的是一个int类型。当主体是一个表达式时,不需要return语句,隐含return该表达式的返回值。
(Mask o1, Mask o2) -> o1.getBrand().compareTo(o2.getBrand())
  1. 参数列表中仅有一个Mask类型的参数,返回的是一个String类型,是该Mask对象的品牌信息。
(Mask mask) -> mask.getBrand()
  1. 参数列表中仅有一个Mask类型的参数,返回的是一个boolean类型,是该Mask对象的类型是否为N95。
(Mask mask) -> mask.getType() == "N95"
  1. 参数列表中没有任何参数,返回的是一个int类型。
() -> 996
  1. 参数列表中有两个int类型的参数,但是没有返回值(void)。在主体中可以写多条语句,不过记住要用{}将其包裹。
(int x, int y) -> {
    System.out.println("万猫学社想对你说:");
    System.out.println("第一个参数是:" + x);
    System.out.println("第二个参数是:" + y);
    System.out.println("两数之和是:" + (x + y));
}

小测试

看了这么多的例子,是不是撸胳膊挽袖子准备大干一场?别急,检验出真知,我们先简单测试一下。以下的Lambda表达式有哪几个是正确的?

  1. () -> {}
  2. () -> "万猫学社"
  3. () -> { "万猫学社" }
  4. () -> { return "万猫学社"; }
  5. () -> return "万猫学社";

请思考片刻…
.
.
.

.
.
.

宣布答案:第1、2和4个是正确的,第3和5个是错误的。我们来逐个分析一下:

  1. () -> {}:正确,这个Lambda表达式没有参数,也没有任何返回。
  2. () -> "万猫学社":正确,这个Lambda表达式没有参数,主体是一个表达式,返回String类型。
  3. () -> { "万猫学社" }:错误, "万猫学社"是一个表达式,不是一个语句,不能使用{}将其包裹,可以修改为() -> "万猫学社"
  4. () -> { return "万猫学社"; }:正确,这个Lambda表达式没有参数,主体是一个语句,使用{}将其包裹,返回String类型。
  5. () -> return "万猫学社"; :错误, return "万猫学社";是一个语句,不是一个表达式,必须使用{}将其包裹,可以修改为() -> { return "万猫学社"; }

如果你全部答对,恭喜你,你已经基本掌握Lambda表达式的基本语法;如果你有答错的,没关系,重新再看一遍,再复习巩固一下。
学习的路上,我与你一起前行。

《死磕Lambda表达式》目录

文章持续更新,微信搜索「 万猫学社 」第一时间阅读。
相关文章
|
人工智能 前端开发 JavaScript
【炫技的代码写法】
【炫技的代码写法】
|
JavaScript 前端开发
📕 重学JavaScript:如何手写一个`reduce`高阶函数?
`reduce` 高阶函数是一个非常常用的数组方法,可以让你用一种简单的方法来处理数组里的元素。 数组就是一串有顺序的东西,比如[1, 2, 3, 4]就是一个数组,里面有四个数字。👌
155 0
|
自然语言处理 Java 编译器
都2023年了,如果不会Lambda表达式、函数式编程?你确定能看懂公司代码?
都2023年了,如果你不会Lambda表达式、函数式编程?你确定能看懂公司代码? 那么建议来了解一下Lambda表达式, 因为它使用简单,易操作,易上手而代码简洁,开发快速,一看就令人很爽😎😎😎 . 其实Lambda表达式接近自然语言,易于理解 , 集万千优点与一身, 比匿名内部类更加完美👉👉👉.下面来简单认识一下今天的主角Lambda表达式吧
120 0
使用 Lambda 表达式的正确姿势,写得太好了叭
Lambda 表达式非常方便,在项目中一般在 stream 编程中用得比较多。 List<Student> studentList = gen(); Map<String, Student> map = studentList .stream() .collect(Collectors.toMap(Student::getId, a -> a, (a, b) -> a)); 理解一个 Lambda 表达式就三步: 1. 确认 Lambda 表达式的类型 2. 找到要实现的方法 3. 实现这个方法 就这三步,没其他的了。而每一步,都非常非常简单,以至于我分别展开讲一下,你就懂了。
(二十)看完这篇类的实例化顺序,考执行顺序的面试题就难不倒你了
一段代码的执行顺序经常会放到面试题或者笔试题中,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,它们的执行顺序,关于这一类题目只要了解了类的实例化顺序,就不会再成为问题。先看一下下面的面试题
死磕Lambda表达式(二):Lambda的使用
函数式接口就是有且仅有一个抽象方法的接口。上面提到的`Comparator<T>`接口,虽然有很多默认方法,但有且仅有一个抽象方法`compare`,所以它仍然是一个函数式接口。
119 0
死磕Lambda表达式(二):Lambda的使用
|
Java 编译器
死磕Lambda表达式(三):更简洁的Lambda
编译器可以通过函数式接口推断出Lambda表达式的参数类型,所以在编写Lambda表达式时,可以省略参数类型。比如:
135 0
死磕Lambda表达式(三):更简洁的Lambda
|
并行计算 Java 编译器
还看不懂同事的代码?Lambda 表达式、函数接口了解一下
还看不懂同事的代码?Lambda 表达式、函数接口了解一下
229 0
|
Java
死磕Lambda表达式(四):常用的函数式接口
在Java8支持Lambda表达式以后,为了满足Lambda表达式的一些典型使用场景,JDK为我们提供了大量常用的函数式接口。它们主要在 java.util.function 包中,下面简单介绍几个其中的接口及其使用示例。
151 0