说出来怕你们不相信,刚接到物业通知,疫情防控升级了,车辆只能出不能进,每户家庭每天可指派 1 名成员上街采购生活用品。这不是谣言,截个图自证清白,出自洛阳市湖北路街道处。


看来事态严峻,这样看似好心,但不一定办好事,去超时抢购的人会更多。不管了,只能窝在家做持久战了。趁这段时间,多分享一些原创文章给你们——有眼福了呀,多储备点知识,疫情结束后肯定能派上大用场。今天分享的主题是《Lambda 表达式》,这也是之前一些读者留言强烈要求我写一写的,不好意思,让你们久等了,现在来满足你们,为时不晚吧?


01、初识 Lambda

Lambda 表达式描述了一个代码块(或者叫匿名方法),可以将其作为参数传递给构造方法或者普通方法以便后续执行。考虑下面这段代码:

() -> System.out.println("沉默王二")

来从左到右解释一下,() 为 Lambda 表达式的参数列表(本例中没有参数),-> 标识这串代码为 Lambda 表达式(也就是说,看到 -> 就知道这是 Lambda),System.out.println("沉默王二") 为要执行的代码,即将“沉默王二”打印到标准输出流。

有点 Java 基础的同学应该不会对 Runnable 接口感到陌生,这是多线程的一个基础接口,它的定义如下:

@FunctionalInterface
public interface Runnable
{
   public abstract void run();
}

Runnable 接口非常简单,仅有一个抽象方法 run();细心的同学会发现一个陌生的注解 @FunctionalInterface,这个注解是什么意思呢?

我看了它的源码,里面有这样一段注释:

Note that instances of functional interfaces can be created with lambda expressions, method references, or constructor references.

大致的意思就是说,通过 @FunctionalInterface 标记的接口可以通过 Lambda 表达式创建实例。具体怎么表现呢?

原来我们创建一个线程并启动它是这样的:

public class LamadaTest {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("沉默王二");
            }
        }).start();
    }
}

通过 Lambda 表达式呢?只需要下面这样:

public class LamadaTest {
    public static void main(String[] args) {
        new Thread(() -> System.out.println("沉默王二")).start();
    }
}

是不是很妙!比起匿名内部类,Lambda 表达式不仅易于理解,更大大简化了必须编写的代码数量。


02、Lambda 语法

每个 Lambda 表达式都遵循以下法则:

( parameter-list ) -> { expression-or-statements }

() 中的 parameter-list 是以逗号分隔的参数。你可以指定参数的类型,也可以不指定(编译器会根据上下文进行推断)。Java 11 后,还可以使用 var 关键字作为参数类型,有点 JavaScript 的味道。

-> 相当于 Lambda 的标识符,就好像见到圣旨就见到了皇上。

{} 中的 expression-or-statements 为 Lambda 的主体,可以是一行语句,也可以多行。

可以通过 Lambda 表达式干很多事情,比如说

1)为变量赋值,示例如下:

Runnable r = () -> { System.out.println("沉默王二"); };
r.run();

2)作为 return 结果,示例如下:

static FileFilter getFilter(String ext)
{
    return (pathname) -> pathname.toString().endsWith(ext);
}

3)作为数组元素,示例如下:

final PathMatcher matchers[] =
{
        (path) -> path.toString().endsWith("txt"),
        (path) -> path.toString().endsWith("java")
};

4)作为普通方法或者构造方法的参数,示例如下:

new Thread(() -> System.out.println("沉默王二")).start();

需要注意 Lambda 表达式的作用域范围。

public static void main(String[] args) {

    int limit = 10;
    Runnable r = () -> {
        int limit = 5;
        for (int i = 0; i < limit; i++)
            System.out.println(i);
    };
}

上面这段代码在编译的时候会提示错误:变量 limit 已经定义过了。

和匿名内部类一样,不要在 Lambda 表达式主体内对方法内的局部变量进行修改,否则编译也不会通过:Lambda 表达式中使用的变量必须是 final 的。


03、Lambda 和 this 关键字

Lambda 表达式并不会引入新的作用域,这一点和匿名内部类是不同的。也就是说,Lambda 表达式主体内使用的 this 关键字和其所在的类实例相同。

来看下面这个示例。

public class LamadaTest {
    public static void main(String[] args) {
        new LamadaTest().work();
    }

    public void work() {
        System.out.printf("this = %s%n", this);

        Runnable r = new Runnable()
        {
            @Override
            public void run()
            {
                System.out.printf("this = %s%n", this);
            }
        };
        new Thread(r).start();
        new Thread(() -> System.out.printf("this = %s%n", this)).start();
    }
}

Tips:%s 代表当前位置输出字符串,%n 代表换行符,也可以使用 \n 代替,但 %n 是跨平台的。

work() 方法中的代码可以分为 3 个部分:

1)单独的 this 关键字

System.out.printf("this = %s%n", this);

其中 this 为 main() 方法中通过 new 关键字创建的 LamadaTest 对象——new LamadaTest()

2)匿名内部类中的 this 关键字

Runnable r = new Runnable()
{
    @Override
    public void run()
    {
        System.out.printf("this = %s%n", this);
    }
};

其中 this 为 work() 方法中通过 new 关键字创建的 Runnable 对象——new Runnable(){...}

3)Lambda 表达式中的 this 关键字

其中 this 关键字和 1)中的相同。

我们来看一下程序的输出结果:

this = com.cmower.java_demo.journal.LamadaTest@3feba861
this = com.cmower.java_demo.journal.LamadaTest$1@64f033cb
this = com.cmower.java_demo.journal.LamadaTest@3feba861

符合我们分析的预期。


04、最后

尽管 Lambda 表达式在简化 Java 编程方面做了很多令人惊讶的努力,但在某些情况下,不当的使用仍然会导致不必要的混乱,大家伙慎用。

好了,我亲爱的读者朋友们,以上就是本文的全部内容了。能在疫情期间坚持看技术文,二哥必须要伸出大拇指为你点个赞

Lambda 表达式入门,看这篇就够了的更多相关文章

  1. React入门看这篇就够了

    摘要: 很多值得了解的细节. 原文:React入门看这篇就够了 作者:Random Fundebug经授权转载,版权归原作者所有. React 背景介绍 React 入门实例教程 React 起源于 ...

  2. [转]React入门看这篇就够了

    摘要: 很多值得了解的细节. 原文:React入门看这篇就够了 作者:Random Fundebug经授权转载,版权归原作者所有. React 背景介绍 React 入门实例教程 React 起源于 ...

  3. [转帖]Zookeeper入门看这篇就够了

    Zookeeper入门看这篇就够了 https://my.oschina.net/u/3796575/blog/1845035 Zookeeper是什么 官方文档上这么解释zookeeper,它是一个 ...

  4. .NET Core实战项目之CMS 第五章 入门篇-Dapper的快速入门看这篇就够了

    写在前面 上篇文章我们讲了如在在实际项目开发中使用Git来进行代码的版本控制,当然介绍的都是比较常用的功能.今天我再带着大家一起熟悉下一个ORM框架Dapper,实例代码的演示编写完成后我会通过Git ...

  5. Zookeeper入门看这篇就够了!!

    Zookeeper是什么 官方文档上这么解释zookeeper,它是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名 ...

  6. ZooKeeper 入门看这篇就够了

    什么是 ZooKeeper? ZooKeeper 是一个分布式的,开放源码的分布式应用程序协同服务.ZooKeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原 ...

  7. EFCore 6.0入门看这篇就够了

    前言 作为一直在dotNet行业耕耘的码农,这几年在大大小小项目中也涉及到了许多ORM框架,比如:EFCore,Dapper,NHibernate,SqlSugar等等,这些ORM都有各自的优缺点,大 ...

  8. Storm入门,看这篇就够了

    部分一:Srorm 简介 1.1 Storm是实时的数据流,Hadoop是批量离线数据 起源背景 Twitter 开源的一个类似于Hadoop的实时数据处理框架 Storm是由Nathan Marz ...

  9. Zookeeper入门看这篇就够了

    https://blog.csdn.net/java_66666/article/details/81015302

  10. Vue开发入门看这篇文章就够了

    摘要: 很多值得了解的细节. 原文:Vue开发看这篇文章就够了 作者:Random Fundebug经授权转载,版权归原作者所有. 介绍 Vue 中文网 Vue github Vue.js 是一套构建 ...

随机推荐

  1. Python 植物大战僵尸代码实现: 图片加载和显示切换

    游戏介绍以前很火的植物大战僵尸游戏, 本想在网上找个python版本游戏学习下,无奈没有发现比较完整的,那就自己来写一个把.图片资源是从github上下载的,因为图片资源有限,只能实现几种植物和僵尸. ...

  2. hadoop传递参数方法总结

    转自:http://blog.csdn.net/xichenguan/article/details/22162813 写MapReduce程序通常要传递各种各样的参数,选择合适的方式来传递参数既能提 ...

  3. Vuex入门实践(中)-多module中的state、mutations、actions和getters

    一.前言 上一篇文章<Vuex入门实践(上)>,我们一共实践了vuex的这些内容: 1.在state中定义共享属性,在组件中可使用[$store.state.属性名]访问共享属性 2.在m ...

  4. JVM之GC(一)

    Java较C而言,最大的区别在于内存管理.JVM设有无用内存空间自动回收复用机制,也就是我们所说的GC. 之前说过,栈是为线程.为函数的执行分配内存的地方,用完即“销毁”,这里留待以后做深入探讨:堆是 ...

  5. 关于Integer 和Double包装类创建对象时的底层解析

    public void method1() { Integer i = new Integer(1); Integer j = new Integer(1); System.out.println(i ...

  6. 重新认识C语言的指针(上)

    ​ 独创性并不是首次观察某种新事物,而是把旧的.很早就是已知的,或者是人人都视而不见的事物当新事物观察,这才证明是有真正的独创头脑 -尼采 本文已经收录至我的GitHub,欢迎大家踊跃star 和 i ...

  7. 【转】20个简化开发任务的 JavaScript库

    原文出处: codegeekz   译文出处: oschina 所谓JavaScript库就是预先写好的可以简化基于JavaScript的应用程序开发的,尤其是Ajax和其它以web为中心的技术的 J ...

  8. 【转】常见Java面试题 – 第三部分:重载(overloading)与重写(overriding)

    ImportNew注: 本文是ImportNew编译整理的Java面试题系列文章之一.你可以从这里查看全部的Java面试系列. 这篇文章介绍的常见面试题是关于重载(overloading)方法和重写( ...

  9. stars-one原创工具——m3u8视频下载合并器(kotlin)

    一款可以下载m3u8.解密ts文件及合并ts文件的视频下载工具 蓝奏云下载地址 github地址 软件对你有帮助的话,不妨赞赏一波!感谢! 程序说明 采用多线程下载,可有效的提高下载速度 内置解密程序 ...

  10. LeetCode 第27题--移除元素

    1. 题目 2.题目分析与思路 3.代码 1. 题目 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2. 你不需要考虑数组 ...