帮助理解Java中的函数对象或函子
有人能解释什么是函子并提供一个简单的例子吗 函子是作为函数的对象 Java没有它们,因为函数在Java中不是一流的对象 但您可以使用接口(类似于命令对象)来近似它们:帮助理解Java中的函数对象或函子,java,functor,Java,Functor,有人能解释什么是函子并提供一个简单的例子吗 函子是作为函数的对象 Java没有它们,因为函数在Java中不是一流的对象 但您可以使用接口(类似于命令对象)来近似它们: public interface Command { void execute(Object [] parameters); } 更新日期:2017年3月18日: 自从我第一次编写这个JDK 8以来,它添加了lambdas。这个包有几个有用的接口。函数对象就是这样。既是对象又是函数的东西 旁白:将函数对象称为“函子”是
public interface Command {
void execute(Object [] parameters);
}
更新日期:2017年3月18日:
自从我第一次编写这个JDK 8以来,它添加了lambdas。这个包有几个有用的接口。函数对象就是这样。既是对象又是函数的东西 旁白:将函数对象称为“函子”是对该术语的严重滥用:另一种“函子”是数学中的核心概念,在计算机科学中具有直接作用(参见“Haskell函子”)。该术语在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"));
...
}
现在,我们可以从上面改写我的示例:
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());
...
}
公共静态无效十次(可运行r){
对于(int i=0;i<10;i++)
r、 run();
}
...
公共类PrintHello实现可运行{
公开募捐{
System.out.println(“你好”)
}
}
---
公共静态真空总管{
...
十次(新PrintHello());
...
}
显然,这个例子是人为的。我们可以使用匿名内部类使这段代码更好一点,但这得到了一般的想法
这里就是问题的症结所在:Runnable
仅可用于不带任何参数且不返回任何有用信息的函数,因此最终为每个作业定义一个新接口。例如,Mohammad Faisal回答中的接口比较器
,一些可关闭的,一些既不可追加,也有两者兼而有之。。提供一种更通用的方法,一种采用语法的方法,是Java8(Java的下一个版本)的一个主要目标,并且被大力推到Java7中。这在lambda演算中的函数抽象机制之后被称为“lambda”。Lambda演算是(也许)最古老的编程语言,也是许多计算机科学的理论基础。当阿隆佐·丘奇(计算机科学的主要创始人之一)发明它时,他用希腊字母lambda表示函数,因此得名 其他语言,包括函数语言(Lisp,ML,Haskell,Erlang等),大多数主要的动态语言(Python,Ruby,JavaScript等)和其他的应用语言(C,斯卡拉,Go,D等)支持某种形式的“lambda文字”,甚至C++现在已经有了(C++ 11),虽然在这种情况下,它们更复杂一些,因为C++缺少自动内存管理,不会为您保存堆栈框架。p> 从每次检查,到函子,再到Java 8 Lambdas(有点) 问题
是可流动的以这个示例类为例,它包含一个:
现在这些“重负荷”检查只需执行一次,只需通过
flush()
和close()
执行布尔检查。虽然这肯定是一种改进,但如何才能完全消除这些函数内检查?如果您能够以某种方式定义一个函数,该函数可以由类存储,然后由
flush()
和close()
…public class WriterForAppendableWChecksInCnstr extends Writer { private final Appendable apbl; private final FlushableFunction flshblFunc; //If only! private final CloseableFunction clsblFunc; //If only! public WriterForAppendableWChecksInCnstr(Appendable apbl) { if(apbl == null) { throw new NullPointerException("apbl"); } this.apbl = apbl; if(apbl instanceof Flushable) { flshblFunc = //The flushable function } else { flshblFunc = //A do-nothing function } if(apbl instanceof Closeable) { clsblFunc = //The closeable function } else { clsblFunc = //A do-nothing function } } //write and append functions go here... public void flush() throws IOException { flshblFunc(); //If only! } public void close() throws IOException { flush(); clsblFunc(); //If only! } }
但是…至少要等到Java8。那么,在8之前版本的Java中如何实现这一点呢?
函子带着。函子基本上是一个Lambda,但它被包装在一个对象中。虽然函数不能作为参数传递给其他函数,但对象可以。所以本质上,函子和lambda是传递函数的一种方式
那么,我们如何在编写器适配器中实现函子呢?我们知道的是
close()
和flush()
仅对Closeable
和Flushable
对象有用。一些可追加的因此,我们可以在类的顶部存储
Flushable
和Closeable
对象:public class WriterForAppendable extends Writer { private final Appendable apbl; private final Flushable flshbl; private final Closeable clsbl; public WriterForAppendable(Appendable apbl) { if(apbl == null) { throw new NullPointerException("apbl"); } //Avoids instanceof at every call to flush() and close() if(apbl instanceof Flushable) { flshbl = apbl; //This Appendable *is* a Flushable } else { flshbl = //?????? //But what goes here???? } if(apbl instanceof Closeable) { clsbl = apbl; //This Appendable *is* a Closeable } else { clsbl = //?????? //And here???? } this.apbl = apbl; } //write and append functions go here... public void flush() throws IOException { flshbl.flush(); } public void close() throws IOException { flush(); clsbl.close(); } }
public WriterForAppendable(Appendable apbl) { if(apbl == null) { throw new NullPointerException("apbl"); } this.apbl = apbl; //Avoids instanceof at every call to flush() and close() flshbl = ((apbl instanceof Flushable) ? (Flushable)apbl : new Flushable() { public void flush() throws IOException { } }); clsbl = ((apbl instanceof Closeable) ? (Closeable)apbl : new Closeable() { public void close() throws IOException { } }); } //the rest of the class goes here... }
package xbn.z.xmpl.lang.functor; import java.io.Closeable; import java.io.Flushable; import java.io.IOException; import java.io.Writer; public class WriterForAppendable extends Writer { private final Appendable apbl; private final Flushable flshbl; private final Closeable clsbl; //Do-nothing functors private static final Flushable FLUSHABLE_DO_NOTHING = new Flushable() { public void flush() throws IOException { } }; private static final Closeable CLOSEABLE_DO_NOTHING = new Closeable() { public void close() throws IOException { } }; public WriterForAppendable(Appendable apbl) { if(apbl == null) { throw new NullPointerException("apbl"); } this.apbl = apbl; //Avoids instanceof at every call to flush() and close() flshbl = ((apbl instanceof Flushable) ? (Flushable)apbl : FLUSHABLE_DO_NOTHING); clsbl = ((apbl instanceof Closeable) ? (Closeable)apbl : CLOSEABLE_DO_NOTHING); } public void write(char[] a_c, int i_ndexStart, int i_ndexEndX) throws IOException { apbl.append(String.valueOf(a_c), i_ndexStart, i_ndexEndX); } public Writer append(char c_c) throws IOException { apbl.append(c_c); return this; } public Writer append(CharSequence c_q) throws IOException { apbl.append(c_q); return this; } public Writer append(CharSequence c_q, int i_ndexStart, int i_ndexEndX) throws IOException { apbl.append(c_q, i_ndexStart, i_ndexEndX); return this; } public void flush() throws IOException { flshbl.flush(); } public void close() throws IOException { flush(); clsbl.close(); } }
“每次”检查现已取消。但是当
无所事事函子可追加的
不是可清洗的或不是可关闭的时,应该存储什么?无所事事的函子…
class CloseableDoesNothing implements Closeable { public void close() throws IOException { } } class FlushableDoesNothing implements Flushable { public void flush() throws IOException { } }
…可以实现为匿名内部类:
public class WriterForAppendable extends Writer { private final Appendable apbl; private final Flushable flshbl; private final Closeable clsbl; public WriterForAppendable(Appendable apbl) { if(apbl == null) { throw new NullPointerException("apbl"); } //Avoids instanceof at every call to flush() and close() if(apbl instanceof Flushable) { flshbl = apbl; //This Appendable *is* a Flushable } else { flshbl = //?????? //But what goes here???? } if(apbl instanceof Closeable) { clsbl = apbl; //This Appendable *is* a Closeable } else { clsbl = //?????? //And here???? } this.apbl = apbl; } //write and append functions go here... public void flush() throws IOException { flshbl.flush(); } public void close() throws IOException { flush(); clsbl.close(); } }
public WriterForAppendable(Appendable apbl) { if(apbl == null) { throw new NullPointerException("apbl"); } this.apbl = apbl; //Avoids instanceof at every call to flush() and close() flshbl = ((apbl instanceof Flushable) ? (Flushable)apbl : new Flushable() { public void flush() throws IOException { } }); clsbl = ((apbl instanceof Closeable) ? (Closeable)apbl : new Closeable() { public void close() throws IOException { } }); } //the rest of the class goes here... }
package xbn.z.xmpl.lang.functor; import java.io.Closeable; import java.io.Flushable; import java.io.IOException; import java.io.Writer; public class WriterForAppendable extends Writer { private final Appendable apbl; private final Flushable flshbl; private final Closeable clsbl; //Do-nothing functors private static final Flushable FLUSHABLE_DO_NOTHING = new Flushable() { public void flush() throws IOException { } }; private static final Closeable CLOSEABLE_DO_NOTHING = new Closeable() { public void close() throws IOException { } }; public WriterForAppendable(Appendable apbl) { if(apbl == null) { throw new NullPointerException("apbl"); } this.apbl = apbl; //Avoids instanceof at every call to flush() and close() flshbl = ((apbl instanceof Flushable) ? (Flushable)apbl : FLUSHABLE_DO_NOTHING); clsbl = ((apbl instanceof Closeable) ? (Closeable)apbl : CLOSEABLE_DO_NOTHING); } public void write(char[] a_c, int i_ndexStart, int i_ndexEndX) throws IOException { apbl.append(String.valueOf(a_c), i_ndexStart, i_ndexEndX); } public Writer append(char c_c) throws IOException { apbl.append(c_c); return this; } public Writer append(CharSequence c_q) throws IOException { apbl.append(c_q); return this; } public Writer append(CharSequence c_q, int i_ndexStart, int i_ndexEndX) throws IOException { apbl.append(c_q, i_ndexStart, i_ndexEndX); return this; } public void flush() throws IOException { flshbl.flush(); } public void close() throws IOException { flush(); clsbl.close(); } }
为了提高效率,这些不执行任何操作的函子应该作为静态最终对象实现。下面是我们课程的最终版本:
public class WriterForAppendable extends Writer { private final Appendable apbl; private final Flushable flshbl; private final Closeable clsbl; public WriterForAppendable(Appendable apbl) { if(apbl == null) { throw new NullPointerException("apbl"); } //Avoids instanceof at every call to flush() and close() if(apbl instanceof Flushable) { flshbl = apbl; //This Appendable *is* a Flushable } else { flshbl = //?????? //But what goes here???? } if(apbl instanceof Closeable) { clsbl = apbl; //This Appendable *is* a Closeable } else { clsbl = //?????? //And here???? } this.apbl = apbl; } //write and append functions go here... public void flush() throws IOException { flshbl.flush(); } public void close() throws IOException { flush(); clsbl.close(); } }
public WriterForAppendable(Appendable apbl) { if(apbl == null) { throw new NullPointerException("apbl"); } this.apbl = apbl; //Avoids instanceof at every call to flush() and close() flshbl = ((apbl instanceof Flushable) ? (Flushable)apbl : new Flushable() { public void flush() throws IOException { } }); clsbl = ((apbl instanceof Closeable) ? (Closeable)apbl : new Closeable() { public void close() throws IOException { } }); } //the rest of the class goes here... }
package xbn.z.xmpl.lang.functor; import java.io.Closeable; import java.io.Flushable; import java.io.IOException; import java.io.Writer; public class WriterForAppendable extends Writer { private final Appendable apbl; private final Flushable flshbl; private final Closeable clsbl; //Do-nothing functors private static final Flushable FLUSHABLE_DO_NOTHING = new Flushable() { public void flush() throws IOException { } }; private static final Closeable CLOSEABLE_DO_NOTHING = new Closeable() { public void close() throws IOException { } }; public WriterForAppendable(Appendable apbl) { if(apbl == null) { throw new NullPointerException("apbl"); } this.apbl = apbl; //Avoids instanceof at every call to flush() and close() flshbl = ((apbl instanceof Flushable) ? (Flushable)apbl : FLUSHABLE_DO_NOTHING); clsbl = ((apbl instanceof Closeable) ? (Closeable)apbl : CLOSEABLE_DO_NOTHING); } public void write(char[] a_c, int i_ndexStart, int i_ndexEndX) throws IOException { apbl.append(String.valueOf(a_c), i_ndexStart, i_ndexEndX); } public Writer append(char c_c) throws IOException { apbl.append(c_c); return this; } public Writer append(CharSequence c_q) throws IOException { apbl.append(c_q); return this; } public Writer append(CharSequence c_q, int i_ndexStart, int i_ndexEndX) throws IOException { apbl.append(c_q, i_ndexStart, i_ndexEndX); return this; } public void flush() throws IOException { flshbl.flush(); } public void close() throws IOException { flush(); clsbl.close(); } }
这个特别的例子来自于。该示例的完整工作版本(包括测试功能)可以在该问题帖子的底部(答案上方)找到。
用枚举实现函子< P >离开我们的代码>编写器<代码> ->代码>可追加的< /代码>示例,让我们来看看另一种实现函子的方法:用枚举。< /p>
例如,此枚举对每个基数方向都有一个
move
函数:public enum CardinalDirection { NORTH(new MoveNorth()), SOUTH(new MoveSouth()), EAST(new MoveEast()), WEST(new MoveWest()); private final MoveInDirection dirFunc; CardinalDirection(MoveInDirection dirFunc) { if(dirFunc == null) { throw new NullPointerException("dirFunc"); } this.dirFunc = dirFunc; } public void move(int steps) { dirFunc.move(steps); } }
它的构造函数需要一个
接口移动间接寻址{ 无效移动(整数步); } 这个接口自然有四个具体的实现,每个方向一个。下面是north的一个简单实现: 类MoveNorth实现MoveInDirection{ 公共无效移动(整数步){ System.out.println(“移动”+步数+“步数北”); } } 使用t Moved 3 steps west.MoveInDirection
对象(它是一个接口,但也可以是一个抽象类):[C:\java_code]java EnumFunctorXmpl Moved 3 steps west. Moved 2 steps north. Moved 15 steps east./** <P>Demonstrates a Functor implemented as an Enum.</P> <P>{@code java EnumFunctorXmpl}</P> **/ public class EnumFunctorXmpl { public static final void main(String[] ignored) { CardinalDirection.WEST.move(3); CardinalDirection.NORTH.move(2); CardinalDirection.EAST.move(15); } } enum CardinalDirection { NORTH(new MoveNorth()), SOUTH(new MoveSouth()), EAST(new MoveEast()), WEST(new MoveWest()); private final MoveInDirection dirFunc; CardinalDirection(MoveInDirection dirFunc) { if(dirFunc == null) { throw new NullPointerException("dirFunc"); } this.dirFunc = dirFunc; } public void move(int steps) { dirFunc.move(steps); } } interface MoveInDirection { void move(int steps); } class MoveNorth implements MoveInDirection { public void move(int steps) { System.out.println("Moved " + steps + " steps north."); } } class MoveSouth implements MoveInDirection { public void move(int steps) { System.out.println("Moved " + steps + " steps south."); } } class MoveEast implements MoveInDirection { public void move(int steps) { System.out.println("Moved " + steps + " steps east."); } } class MoveWest implements MoveInDirection { public void move(int steps) { System.out.println("Moved " + steps + " steps west."); } }
f.apply(x)
x.map(f)
interface Functor<T> { Functor<R> map(Function<T, R> f); }