美文网首页我不想再做Java小白了
Lambda 表达式入门,看这篇就够了

Lambda 表达式入门,看这篇就够了

作者: 沉默王二 | 来源:发表于2020-02-09 08:15 被阅读0次

    说出来怕你们不相信,刚接到物业通知,疫情防控升级了,车辆只能出不能进,每户家庭每天可指派 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 表达式入门,看这篇就够了

        本文链接:https://www.haomeiwen.com/subject/nvwmxhtx.html