Java 什么是;“编码为数据”;什么意思?

Java 什么是;“编码为数据”;什么意思?,java,lambda,java-8,anonymous-inner-class,Java,Lambda,Java 8,Anonymous Inner Class,我最近遇到了一个来自EclipseCon2014的例子,在第5页,他们说,“Lambda表达式允许您将代码视为数据” 我还遇到了这个示例代码 button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { System.out.println("button clicked"); } }); 摘自RichardWarburton的“J

我最近遇到了一个来自EclipseCon2014的例子,在第5页,他们说,“Lambda表达式允许您将代码视为数据”

我还遇到了这个示例代码

button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent event) {
        System.out.println("button clicked");
    }
});
摘自RichardWarburton的“Java8Lambdas:实用函数编程”,他在书中说

“这实际上是一个使用代码作为数据的示例,我们给出了 按钮表示动作的对象。“


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

当您将功能作为参数传递给另一个方法时,例如当有人单击类似于示例代码的按钮时,应该采取什么操作

Lambda表达式允许您这样做,将功能视为方法参数


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

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

在Java的黄金时代,没有方便的范例将功能从调用者传递给接收者。您必须使用某种方法(通常通过“”设计模式)将一个类拼凑在一起,然后将其传递给接收者

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

这种范式转换为java.util.Stream铺平了道路,它接受lambda表达式,告诉集合执行一项功能


莫里斯·纳夫塔林(Maurice Naftalin)的新书非常清晰、简洁、完整地阐述了整个主题

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

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

例如,您可能会想象,在
按钮内部它看起来像这样:

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);
        }
    }
}
class按钮{
私有ActionListener[]侦听器=新ActionListener[100];
私有整数计数=0;
public void addActionListener(ActionListener listener){
侦听器[计数]=侦听器;
++计数;
}
//单击按钮时以某种方式调用
void notifyListeners(){
ActionEvent theEvent=新的ActionEvent(…);
对于(int i=0;i
本质上,
按钮
将函数列表保存在一个数组中:这将代码视为数据。在大多数情况下,
ActionListener
除了引用对
actionPerformed
的特定重写之外,没有其他用途

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

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

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

将代码视为数据的思想与具有一流函数的编程语言的概念密切相关。请参阅有关此主题的详细信息。在本文中,我将讨论Java是否具有一流的函数,但这篇文章还讨论了一些其他问题

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

  • 可以作为参数传递给其他函数
  • 可以作为值从其他函数返回
  • 可以指定给变量
  • 可以存储在数据结构中
这些都是您对数据所做的事情。如果你能用函数做同样的事情,那就像把代码当作数据一样

如果仔细观察lambda是如何添加到Java编程语言中的,您会发现lambda实际上被转换为函数接口的实例。因此,它是某个对象的实例,因此是类
对象的后代,与Java中的所有对象一样,它有
equals()、hashCode()、getClass()
等方法,引用可以与
=
等进行比较。但是,您显然不希望依赖这些。有关更多讨论,请参见我的。实际上,在Java中使用lambdas时,感觉就像是将代码作为参数传递,或者将其分配给变量。比如说,

list.replaceAll(x -> doSomething(x));

Predicate<String> pred = s -> s.length() > 5;
list.replaceAll(x->doSomething(x));
谓词pred=s->s.length()>5;

你最终真的没有考虑到这样一个事实,即在幕后,lambda是作为函数接口实例的对象。

我猜它指的是将方法作为值传递,lambda给出了这样做的假象。值被视为数据,“代码”可能是指代码块,该代码块与任何将函数视为基本类公民的函数语言(将函数作为另一个函数的输入的概念)类似。Th