首页 > 解决方案 > 我无法理解 lambda 表达式在 Java 中的工作原理

问题描述

我介于初学者和中级 Java 程序员之间,几天前,函数式编程的神秘概念引起了我的注意。我习惯于 OOP 实践,并且没有关于在 Java 中使用 lambda 表达式对我的影响。下面是我的困惑的一个例子

Runnable r1 = new Runnable() {
  @Override
  public void run () {
     System.out.println("Prior to Java 8");
   }
};

//Runnable using lambda expression
Runnable r2 = () - > {
    System.out.println("From Java 8");
};

我不知道将 r2 分配给 lambda 表达式应该是什么意思。接口的整个对象是如何分配给只打印出一条消息的代码块的?函数式编程的抽象级别对我来说几乎没有意义,任何回复都将不胜感激。

标签: javafunctional-programming

解决方案


本质上,您的第二个块 ( r2) 是语法糖。请注意其中的内容r2是如何少得多的文本。如果你比较,它会变得更好,比如:

Comparator stringLength = new Comparator<String>() {
    public int compare(String a, String b) {
        return a.length() - b.length();
    }
};

相对:

Comparator stringLength = (a, b) -> a.length() - b.length();

但让我们先集中注意力r1

这本身也是语法糖!它的简称:

public void methodWeAreIn() {
    class MethodLocalClassWithoutAnImportantName implements Runnable {
        public void run() { System.out.println("boo"); }
    }

    Runnable r1 = new MethodLocalClassWithoutAnImportantName();
}

关键是:您首先定义一个类,然后创建该类的单个实例,然后丢弃它的特定类型性质(将其分配给 type 的变量Runnable。就像 in 一样List<String> x = new ArrayList<String>();,您失去了调用trimToSizeensureCapacity,这些方法仅存在于 ArrayList 中,而不存在于 List 本身中。)这不是一件坏事:在这个特定的代码段中,这并不重要。

这就是重点:这里的类型 ( MethodLocalClassWithoutAnImportantName)与类型完全无关——代码库中的任何方法都没有将其中一个作为参数,也没有方法返回它。它就像一个反接口:接口的存在只是为了有一个类型来实现或放入方法签名(作为返回类型或参数)。这堂课的重点是相反的。重点不在于类结构。这个类的重点仅仅是它里面的实现。毕竟这是 OO 的一部分——有时你实现了一个接口并且没有定义任何新的方法或字段,你只是在实现接口并且可能覆盖超类中的东西。

重新考虑这一切意味着什么更为明智。您并没有定义一个新类然后创建一个实例。你实际上只是拿了一些代码,而不是运行它,你把它塞进一个信封里。

现在你可以把这个信封交给另一个方法(它可以选择也交给它,或者打开它并运行它),或者重复运行它,或者稍后在另一个线程中运行它等等。是的,在r1(以及我的方法本地类示例),“信封”是一个对象,但这只是一种方便的方法,练习的重点不是创建新类型,而是编写可以四处传播的代码。

Lambdas 只是让那个正式的。

注意:r2不是精确的语法糖;但是除非你做你不应该做的事情,否则你无法区分:尝试将 r2 视为具有标识的对象。如果你synchronized (r2),或者尝试类似的事情System.identityHashCOde(r2);,会发生奇怪的事情。关键是不要那样做。你为什么想要?


推荐阅读