帮助理解Java中的函数对象或函子

帮助理解Java中的函数对象或函子,java,functor,Java,Functor,有人能解释什么是函子并提供一个简单的例子吗 函子是作为函数的对象 Java没有它们,因为函数在Java中不是一流的对象 但您可以使用接口(类似于命令对象)来近似它们: public interface Command { void execute(Object [] parameters); } 更新日期:2017年3月18日: 自从我第一次编写这个JDK 8以来,它添加了lambdas。这个包有几个有用的接口。函数对象就是这样。既是对象又是函数的东西 旁白:将函数对象称为“函子”是

有人能解释什么是函子并提供一个简单的例子吗

函子是作为函数的对象

Java没有它们,因为函数在Java中不是一流的对象

但您可以使用接口(类似于命令对象)来近似它们:

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()仅对CloseableFlushable对象有用。一些可追加的是可流动的,一些可关闭的,一些既不可追加,也有两者兼而有之。

因此,我们可以在类的顶部存储FlushableCloseable对象:

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);
   }
}

它的构造函数需要一个MoveInDirection对象(它是一个接口,但也可以是一个抽象类):

接口移动间接寻址{ 无效移动(整数步); }

这个接口自然有四个具体的实现,每个方向一个。下面是north的一个简单实现:

类MoveNorth实现MoveInDirection{ 公共无效移动(整数步){ System.out.println(“移动”+步数+“步数北”); } }

使用t Moved 3 steps west.
/**
   <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.");
   }
}
[C:\java_code]java EnumFunctorXmpl Moved 3 steps west. Moved 2 steps north. Moved 15 steps east.
f.apply(x)
x.map(f)
interface Functor<T> {
    Functor<R> map(Function<T, R> f);
}