"Code as Data" 是什么意思?
What does "Code as Data" mean?
我最近在 EclipseCon 2014 上遇到了 presentation,在第 5 页他们说 "Lambda expressions allow you to treat code as data" .
我也遇到了这个示例代码
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.out.println("button clicked");
}
});
来自 Richard Warburton 的 "Java 8 Lambdas: Pragmatic Functional Programming" 他说
"这实际上是一个使用代码作为数据的例子——我们给出
按钮代表动作的对象。
关于 Lambda 表达式 code as data 是什么意思 and/or 匿名内部 class?
当您将功能作为参数传递给另一个方法时,例如当有人像您的示例代码那样单击按钮时应该采取什么操作。
Lambda 表达式使您能够做到这一点,将功能视为方法参数 = code as data.
有关详细信息和 lambda 代码示例,请参阅 oracle link。
意思是你写的程序代码也是一个数据可以作为参数传递给另一个method
并由程序操纵。
在 Java 的黄金时代,没有方便的范例将功能从调用者传递到接收者。您必须使用某种方法(通常通过“Command”设计模式)将 class 组合在一起,然后将其传递给接收者。
Java 8 Lambda 通过引入 Lambda 表达式改变了范式。忘记这些是如何在运行时表示的,Lambda 对开发人员来说就像是可以传递给方法的纯代码。代码作为数据!
这种范式转变为 java.util.Stream 接受 lambda 表达式铺平了道路,这些 lambda 表达式告诉集合执行一项功能。
莫里斯·纳夫塔林 (Maurice Naftalin) 的新书 Mastering Lambdas - Java Programming in a Multi-Core World 对整个主题进行了清晰、简洁和完整的处理。
代码永远是数据!程序的字节码指令存储在内存中。程序员无法直接读写这块内存,但它就在那里。
当我们谈论 "treating" 代码作为数据时,我们指的是以我们通常认为的 "data" 的方式使用和组织的方式存储对该内存的引用。 =16=]
例如,人们可能会想象 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 表达式只是增加了概念上的强调和简短的语法。 (由于它们的实施,在大多数情况下也会提高性能。)
当我们仅使用对象来实现特定方法而不是存储值时,Lambda 可以让我们更清楚地表达我们的意图。
从技术上讲,这都是通过间接完成的。 ActionListener
不保存代码:相反,虚拟机以某种方式知道(我们不知道)它指向内存中保存指向代码的指针的特定结构。因此,对代码的某种引用实际上是在传递,因此“将代码视为数据”。
"code as data" 的想法与具有 first-class 函数的编程语言的概念密切相关。看Wikipedia article on this topic. In this other answer我说的是Java是否有first-class功能,但是那篇文章也讨论了其他一些问题。
维基百科文章中的定义(引用了 Abelson & Sussman,计算机程序的结构和解释,第 1.3 节)特别提到了使它们成为函数的以下特征 "first-class":
- 可以作为参数传递给其他函数
- 可以作为其他函数的值返回
- 可以赋值给变量
- 可以存储在数据结构中
这些都是您对数据所做的事情。如果你可以用函数做同样的事情,那就像是对待 "code as data."
如果您仔细研究如何将 lambda 添加到 Java 编程语言中,您会发现 lambda 实际上已转换为函数接口的实例。因此,它是某个对象的实例,因此是 class Object
的后代,并且像 Java 中的所有对象一样,它具有 equals(), hashCode(), getClass()
等方法和引用可以与 ==
等进行比较。但是,明确不鼓励您依赖其中任何一个。有关更多讨论,请参阅我的 other answer。在实践中,当您在 Java 中使用 lambda 时,感觉就像您将代码作为参数传递,或将其分配给变量。例如,
list.replaceAll(x -> doSomething(x));
Predicate<String> pred = s -> s.length() > 5;
你真的没有想到,在幕后,lambda 是函数接口实例的对象。
我最近在 EclipseCon 2014 上遇到了 presentation,在第 5 页他们说 "Lambda expressions allow you to treat code as data" .
我也遇到了这个示例代码
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.out.println("button clicked");
}
});
来自 Richard Warburton 的 "Java 8 Lambdas: Pragmatic Functional Programming" 他说
"这实际上是一个使用代码作为数据的例子——我们给出 按钮代表动作的对象。
关于 Lambda 表达式 code as data 是什么意思 and/or 匿名内部 class?
当您将功能作为参数传递给另一个方法时,例如当有人像您的示例代码那样单击按钮时应该采取什么操作。
Lambda 表达式使您能够做到这一点,将功能视为方法参数 = code as data.
有关详细信息和 lambda 代码示例,请参阅 oracle link。
意思是你写的程序代码也是一个数据可以作为参数传递给另一个method
并由程序操纵。
在 Java 的黄金时代,没有方便的范例将功能从调用者传递到接收者。您必须使用某种方法(通常通过“Command”设计模式)将 class 组合在一起,然后将其传递给接收者。
Java 8 Lambda 通过引入 Lambda 表达式改变了范式。忘记这些是如何在运行时表示的,Lambda 对开发人员来说就像是可以传递给方法的纯代码。代码作为数据!
这种范式转变为 java.util.Stream 接受 lambda 表达式铺平了道路,这些 lambda 表达式告诉集合执行一项功能。
莫里斯·纳夫塔林 (Maurice Naftalin) 的新书 Mastering Lambdas - Java Programming in a Multi-Core World 对整个主题进行了清晰、简洁和完整的处理。
代码永远是数据!程序的字节码指令存储在内存中。程序员无法直接读写这块内存,但它就在那里。
当我们谈论 "treating" 代码作为数据时,我们指的是以我们通常认为的 "data" 的方式使用和组织的方式存储对该内存的引用。 =16=]
例如,人们可能会想象 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 表达式只是增加了概念上的强调和简短的语法。 (由于它们的实施,在大多数情况下也会提高性能。)
当我们仅使用对象来实现特定方法而不是存储值时,Lambda 可以让我们更清楚地表达我们的意图。
从技术上讲,这都是通过间接完成的。 ActionListener
不保存代码:相反,虚拟机以某种方式知道(我们不知道)它指向内存中保存指向代码的指针的特定结构。因此,对代码的某种引用实际上是在传递,因此“将代码视为数据”。
"code as data" 的想法与具有 first-class 函数的编程语言的概念密切相关。看Wikipedia article on this topic. In this other answer我说的是Java是否有first-class功能,但是那篇文章也讨论了其他一些问题。
维基百科文章中的定义(引用了 Abelson & Sussman,计算机程序的结构和解释,第 1.3 节)特别提到了使它们成为函数的以下特征 "first-class":
- 可以作为参数传递给其他函数
- 可以作为其他函数的值返回
- 可以赋值给变量
- 可以存储在数据结构中
这些都是您对数据所做的事情。如果你可以用函数做同样的事情,那就像是对待 "code as data."
如果您仔细研究如何将 lambda 添加到 Java 编程语言中,您会发现 lambda 实际上已转换为函数接口的实例。因此,它是某个对象的实例,因此是 class Object
的后代,并且像 Java 中的所有对象一样,它具有 equals(), hashCode(), getClass()
等方法和引用可以与 ==
等进行比较。但是,明确不鼓励您依赖其中任何一个。有关更多讨论,请参阅我的 other answer。在实践中,当您在 Java 中使用 lambda 时,感觉就像您将代码作为参数传递,或将其分配给变量。例如,
list.replaceAll(x -> doSomething(x));
Predicate<String> pred = s -> s.length() > 5;
你真的没有想到,在幕后,lambda 是函数接口实例的对象。