帮助理解 Java 中的函数对象或函子
有人可以解释什么是函子并提供一个简单的例子吗?
函数对象就是这样。既是对象又是函数的东西。
题外话:将函数对象称为“函子”是对该术语的严重滥用:另一种“函子”是数学中的中心概念,并且在计算机科学中具有直接作用(参见“Haskell Functors”)。该术语在ML中的使用方式也略有不同,因此除非您在Java中实现这些概念之一(您可以!),否则请停止使用此术语。它使简单的事情变得复杂。
回到答案:Java没有“一类函数”,也就是说,你不能把一个函数作为参数传递给一个函数。这在多个级别上是正确的,在语法上,在字节代码表示中,并且类型系统缺少“函数构造函数”
换句话说,你不能写这样的东西:
public static void tentimes(Function f){
for(int i = 0; i < 10; i++)
f();
}
...
public static void main{
...
tentimes(System.out.println("hello"));
...
}
这真的很烦人,因为我们希望能够做一些事情,比如拥有图形用户界面库,您可以在其中将“回调”函数与单击按钮相关联。
那么我们该怎么办呢?
好吧,一般的解决方案(由其他海报讨论)是使用我们可以调用的单个方法定义一个接口。例如,Java一直使用一个调用这些类型的接口,它看起来像这样:Runnable
public interface Runnable{
public void run();
}
现在,我们可以从上面重写我的例子:
public static void tentimes(Runnable r){
for(int i = 0; i < 10; i++)
r.run();
}
...
public class PrintHello implements Runnable{
public void run{
System.out.println("hello")
}
}
---
public static void main{
...
tentimes(new PrintHello());
...
}
显然,这个例子是人为的。我们可以使用匿名内部类使此代码更好一些,但这得到了一般的想法。
这是分解的地方:仅适用于不采用任何参数的函数,并且不返回任何有用的东西,因此您最终为每个作业定义了一个新接口。例如,穆罕默德·费萨尔(Mohammad Faisal)答案中的界面。提供一种更通用的方法,一种采用语法的方法,是Java 8(Java的下一个版本)的主要目标,并且被大力推动包含在Java 7中。这被称为Lambda演算中函数抽象机制之后的“lambda”。Lambda Calculus既是(也许)最古老的编程语言,也是计算机科学的理论基础。当阿朗佐·丘奇(Alonzo Church)(计算机科学的主要创始人之一)发明它时,他使用希腊字母lambda来表示函数,因此得名。Runnable
Comparator
其他语言,包括函数式语言(Lisp,ML,Haskell,Erlang等),大多数主要的动态语言(Python,Ruby,JavaScript等)和其他应用程序语言(C#,Scala,Go,D等)都支持某种形式的“Lambda Literal”。即使C++现在也有它们(自C++11以来),尽管在这种情况下,它们会更复杂,因为C++缺乏自动内存管理,并且不会为您保存堆栈帧。
函子是一个函数的对象。
Java没有它们,因为函数不是Java中的第一类对象。
但是你可以用接口来近似它们,就像一个 Command 对象一样:
public interface Command {
void execute(Object [] parameters);
}
更新时间 18-三月-2017:
自从我第一次写这个JDK 8以来,它增加了lambda。java.util.function 包有几个有用的接口。