“代码为数据”是什么意思?

时间:2015-02-01 19:44:55

标签: java lambda java-8 anonymous-inner-class

我最近遇到了来自EclipseCon 2014的presentation,在第5页,他们说 &#34; Lambda表达式允许您将代码视为数据&#34; < / strong>即可。

我也遇到了这个示例代码

button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent event) {
        System.out.println("button clicked");
    }
});

来自&#34; Java 8 Lambdas:实用功能编程&#34;理查德沃伯顿在那里他说

&#34;这实际上是使用代码作为数据的一个例子 - 我们给出了 按钮表示动作的对象。&#34;

代码作为数据对于Lambda表达式和/或匿名内部类是什么意思?

5 个答案:

答案 0 :(得分:5)

当您将功能作为参数传递给另一个方法时,例如当有人单击像您的示例代码那样的按钮时应采取的操作。

Lambda表达式使您能够执行此操作,将功能视为方法参数 = code as data

有关更多信息和lambda代码示例,请参阅oracle link

答案 1 :(得分:3)

“代码作为数据”的概念与具有一等函数的编程语言的概念密切相关。有关此主题,请参阅Wikipedia article。在这篇other answer中我谈到Java是否具有一流的功能,但该文章也讨论了其他一些问题。

维基百科文章(引用Abelson&amp; Sussman,计算机程序的结构和解释,第1.3节)中的定义特别提到了使其成为“一流”的功能的以下特征:

  • 可以作为参数传递给其他函数
  • 可以作为其他函数的值返回
  • 可以分配给变量
  • 可以存储在数据结构中

这些都是您对数据所做的事情。如果你可以使用函数执行相同的操作,那就像将代码视为数据一样。

如果仔细研究如何将lambdas添加到Java编程语言中,您将看到lambda实际上已转换为功能接口的实例。因此,它是某个对象的实例,因此是类Object的后代,并且与Java中的所有对象一样,它具有equals(), hashCode(), getClass()等方法,并且可以将引用与{{1}进行比较等等。但是,明确不鼓励您依赖任何此类内容。有关其他讨论,请参阅我的other answer。实际上,当你在Java中使用lambdas时,感觉就像你将代码作为参数传递,或者将它分配给变量。例如,

==

你真的最终没有考虑到这样一个事实:在lambdas中,lambda是作为功能接口实例的对象。

答案 2 :(得分:1)

这意味着您编写的程序代码也是数据,可以作为参数传递给另一个method并由程序操作。< / p>

答案 3 :(得分:1)

在Java的黄金时代,没有方便的范例将函数从调用者传递给接收者。你必须使用某种方法(通常通过&#34; Command&#34;设计模式)将一个类组合在一起,然后将其传递给接收者。

Java 8 Lambdas通过引入Lambda表达式改变了范式。忘记这些如何表示给运行时,Lambdas在开发人员看来是可以传递给方法的纯代码。代码作为数据!

这种范式转换为java.util.Stream提供了接受lambda表达式的方式,这些表达式告诉集合执行一项功能。

对于整个主题的清晰,简洁和完整的处理是Maurice Naftalin的新书Mastering Lambdas - Java Programming in a Multi-Core World

答案 4 :(得分:1)

代码始终是数据!程序的字节码指令存储在存储器中。程序员没有对此内存的直接读写访问权限,但它就在那里。

当我们谈论将“处理”代码作为数据时,我们指的是以对我们通常认为“数据”的方式使用和组织的方式存储对该内存的引用。

例如,可以想象在button内部看起来像这样:

class Button {
    private ActionListener[] listeners = new ActionListener[100];
    private int count = 0;

    public void addActionListener(ActionListener listener) {
        listeners[count] = listener;
        ++count;
    }

    // called somehow when the button is clicked
    void notifyListeners() {
        ActionEvent theEvent = new ActionEvent(...);
        for(int i = 0; i < count; ++i) {
            listeners[i].actionPerformed(theEvent);
        }
    }
}

基本上Button保留了数组中的函数列表:这是将代码视为数据。在大多数情况下,ActionListener除了引用actionPerformed的特定覆盖外,没有任何其他用途。

由于所有Java实例方法都是虚拟的,因此我们始终可以将代码视为数据。 AWT / Swing精心设计的事件监听框架证明了这一点。 Lambda表达式只是增加了概念强调和短语法。 (由于它们的实现,在大多数情况下也是性能提升。)

当我们仅使用对象来实现特定方法而不是存储值时,Lambdas允许我们更清楚地表达我们的意图。

从技术上讲,这都是通过间接完成的。 ActionListener不包含代码:相反,虚拟机以某种方式(我们并不知情)知道它指向内存中包含指向代码的指针的特定结构。所以对代码的某种引用是实际传递的内容,因此“代码视为数据”。