Java的Lambda表达式

函数式编程(Functional Programming)是把函数作为基本运算单元,函数可以作为变量,可以接收函数,还可以返回函数。历史上研究函数式编程的理论是Lambda演算,所以我们经常把支持函数式编程的编码风格称为Lambda表达式。

在Java程序中,我们经常遇到一大堆单方法接口,即一个接口只定义了一个方法:

  • Comparator
  • Runnable
  • Callable

Comparator为例,我们想要调用 Arrays.sort()时,可以传入一个 Comparator实例,以匿名类方式编写如下:

String[] array = ...

Arrays.sort(array, new Comparator() {
    public int compare(String s1, String s2) {
        return s1.compareTo(s2);
    }
});

上述写法非常繁琐。从Java 8开始,我们可以用Lambda表达式替换单方法接口。改写上述代码如下:

public class Main {
    public static void main(String[] args) {
        String[] array = new String[] { "Apple", "Orange", "Banana", "Lemon" };
        Arrays.sort(array, (s1, s2) -> {
            return s1.compareTo(s2);
        });
        // 输出:Apple, Banana, Lemon, Orange
        System.out.println(String.join(", ", array));
    }
}

观察Lambda表达式的写法,它只需要写出方法定义:

(s1, s2) -> {
    return s1.compareTo(s2);
}

其中,参数是 (s1, s2),参数类型可以省略,因为编译器可以自动推断出 String类型。 -> { ... }表示方法体,所有代码写在内部即可。返回值的类型也是由编译器自动推断的,这里推断出的返回值是 int,因此,只要返回 int,编译器就不会报错。

并且不用书写 class定义,这样的写法是不是非常简洁。

如果只有一行 return xxx的代码,完全可以用更简单的写法:

Arrays.sort(array, (s1, s2) -> s1.compareTo(s2));

FunctionalInterface

我们把只定义了单方法的接口称之为 FunctionalInterface,用注解 @FunctionalInterface标记。这里以 Callable接口为例:

@FunctionalInterface
public interface Callable {
    V call() throws Exception;
}

再来看 Comparator接口:

@FunctionalInterface
public interface Comparator {

    int compare(T o1, T o2);

    boolean equals(Object obj);

    default Comparator reversed() {
        return Collections.reverseOrder(this);
    }

    default Comparator thenComparing(Comparator other) {
        ...

    }
    ...

}

这时候看到 Comparator接口,一些人认为它不应该是定义单方法的接口。

如果你细看,虽然 Comparator接口有很多方法,但只有一个抽象方法 int compare(T o1, T o2),其他的方法都是 default方法或 static方法。还有 boolean equals(Object obj);Object定义的方法,不算在接口方法内。因此, Comparator也是一个 FunctionalInterface

看到这有兴趣的还能再补充下

方法引用

除了Lambda表达式,我们还可以直接传入方法引用。例如:

public class Main {
    public static void main(String[] args) {
        String[] array = new String[] { "Apple", "Orange", "Banana", "Lemon" };
        Arrays.sort(array, Main::cmp);
        System.out.println(String.join(", ", array));
    }

    static int cmp(String s1, String s2) {
        return s1.compareTo(s2);
    }
}

上述代码在 Arrays.sort()中直接传入了静态方法 cmp的引用,用 Main::cmp表示。

因此,所谓方法引用,是指如果某个 方法签名和接口恰好一致,就可以直接传入方法引用。

那什么是 方法签名和接口一致呢?

方法参数一致,返回类型相同,我们说两者的 方法签名一致。(不看方法名称,也不看类的继承关系)

Comparator<string></string>接口定义的方法是 int compare(String, String),和静态方法 int cmp(String, String)就属于方法签名一致,我们可以直接把方法名作为Lambda表达式传入:

Arrays.sort(array, Main::cmp);

我们再看看如何引用实例方法:

public class Main {
    public static void main(String[] args) {
        String[] array = new String[] { "Apple", "Orange", "Banana", "Lemon" };
        Arrays.sort(array, String::compareTo);
        System.out.println(String.join(", ", array));
    }
}

不但可以编译通过,而且运行结果也是一样的,这说明 String.compareTo()方法也符合Lambda定义。

观察 String.compareTo()的方法定义:

public final class String {
    public int compareTo(String o) {
        ...

    }
}

有人会疑惑了:这个方法的签名只有一个参数,为什么和 int Comparator<string>.compare(String, String)</string>能匹配呢?

因为实例方法有一个隐含的 this参数, String类的 compareTo()方法在实际调用的时候,第一个隐含参数总是传入 this,相当于静态方法:

public static int compareTo(this, String o);

所以, String.compareTo()方法也可作为方法引用传入。

Original: https://www.cnblogs.com/xnmk-zhan/p/15549793.html
Author: xnmk
Title: Java的Lambda表达式

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/590683/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • python: can’t open file ‘upload.py’: [Errno 2] No such file or directory

    为了发博客方便,参考别人的文章(见参考文章:[1][2]),使用 Metaweblog 和 pycnblog([3])插件实现相关功能,将本地markdown文件同步至博客园。使用…

    数据库 2023年6月14日
    083
  • jdbc-使用工具类

    package com.cqust; import com.cqust.utils.JDBCUtil; import java.sql.Connection;import java…

    数据库 2023年6月11日
    066
  • LeetCode刷题笔记-简单入门题

    分割平衡字符串 在一个 平衡字符串 中,’L’ 和 ‘R’ 字符的数量是相同的。 给你一个平衡字符串 s,请你将它分割成尽可能多的平…

    数据库 2023年6月11日
    092
  • Failed to write to mysql.slow_log

    最近将一MySQL数据库的系统变量log_output从file调整为table后,偶尔会收到告警邮件,告警邮件内容为: Failed to write to mysql.slow…

    数据库 2023年5月24日
    085
  • Linux

    1、关机命令 命令 说明 sync 将数据由内存同步到硬盘中 shutdown 关机 shutdown -h 10 10分钟后关机 shutdown -h now 立马关机 shu…

    数据库 2023年6月16日
    0102
  • MySQL索引分类及相关概念辨析

    本文链接:https://www.cnblogs.com/ibigboy/p/16198243.html 之前的一篇《MySQL索引底层数据结构及原理深入分析》很受读者欢迎,成功地…

    数据库 2023年6月11日
    090
  • 普通 Docker 与 Kubernetes 对比

    Docker提供基本容器管理 API 和容器镜像文件格式Kubernetes 管理运行容器的(物理或虚拟)主机群集,如果 Docker 是 OCP 的”内核&#8221…

    数据库 2023年6月14日
    070
  • SQL语句的整合

    基础语法 https://blog.csdn.net/m0_37989980/article/details/103413942 CRUD 提供给数据库管理员的基本操作,CRUD(…

    数据库 2023年5月24日
    097
  • 常用函数封装汇总

    常用函数封装 获取某日期若干个工作日后的日期 * &#x53C2;&#x6570;: * time: [String] &#x7ED9;&#x5B9…

    数据库 2023年6月11日
    0108
  • Dubbo源码(二)-SPI源码

    假设你已经知道Dubbo SPI的使用方式,不知道的请出门左转: Dubbo源码地址: 本文使用版本:2.6.x 获取所有的拓展类 Dubbo SPI 的相关逻辑被封装在了 Ext…

    数据库 2023年6月11日
    081
  • 关闭 Windows 10 鼠标移到任务栏图标上显示的预览小卡片(小窗口)

    Windows 10 在默认情况下,鼠标移到任务栏的应用程序窗口图标上,会显示一个类似缩略的小窗口预览卡片的窗口视图。在需要频繁切换窗口的时候,鼠标很容易就移到当前窗口或其他窗口的…

    数据库 2023年6月16日
    0141
  • [Mysql]Ubuntu如何安装Mysql+启用远程连接[完整版]

    嗯。以下是我踩了好几个小时的所有坑总结出来的血泪史。我希望我能帮你少踩几个坑。正常情况下,一步一步地,不会有任何问题。 [En] Yeah. The following is th…

    数据库 2023年5月24日
    098
  • SpringBoot下的文件上传

    ; 代码很简单。已经放到码云了,码云地址:https://gitee.com/zhang-zhixi/springboot-upload.git posted @2022-04-2…

    数据库 2023年6月14日
    077
  • 如何识别 SQL Server 的版本

    本文介绍如何识别当前的Microsoft SQL Server 版本号和相应的产品或Service Pack 级别。同时介绍如何识别正在使用的SQL Server 具体版本。 如何…

    数据库 2023年6月11日
    082
  • linux常用命令(持续更新中…)

    查看所有开机启动服务:systemctl list-unit-files # 按Enter翻页 查看所有开机启动服务:systemctl list-unit-files | gre…

    数据库 2023年6月14日
    078
  • 2022-8-31 jsp el表达式

    jsp 注意:1、JSP脚本片段中只能出现java代码,不能出现HTML元素。在 访问JSP时,JSP引擎翻译JSP页面中的脚本片段。2、JSP脚本片段中的java代码必须严格遵守…

    数据库 2023年6月14日
    070
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球