在《Code Complete》一书中,作者谈论了编程 进入 一种语言(而不是用一种语言编程)。他的意思是,您不应该受到所选编程语言的限制。

回调是一个经常使用的功能。我很感兴趣:将回调编程为 java 语言的最优雅的方法是什么?

有帮助吗?

解决方案

查看这篇文章:

http://www.onjava.com /pub/a/onjava/2003/05/21/delegates.html

回调本质上是一个特殊情况,代表(因为C#有它们),文章给出了一个类似于C#委托的东西的实现,在java中。

其他提示

Java会针对各种情况使用各种回调。自从AWT听众最古老的时代以来,Java一直都是关于回调的。

有两种基本的“味道”。 Java回调。第一个是实现接口方法:

public class MyThing implements StateChangeListener {

   //this method is declared in StateChangeListener
   public void stateChanged() {
      System.out.println("Callback called!");
   }

   public MyThing() {
      //Here we declare ourselves as a listener, which will eventually
      //lead to the stateChanged method being called.
      SomeLibraryICareAbout.addListener(this);
   }
}

Java回调的第二种风格是匿名内部类:

public class MyThing {

   public MyThing() {
      //Here we declare ourselves as a listener, which will eventually
      //lead to the stateChanged method being called.
      SomeLibraryICareAbout.addListener( new StateChangeListener() {
          //this method is declared in StateChangeListener
          public void stateChanged() {
              System.out.println("Callback called!");
          }
      });
   }
}

还有其他方法,包括使用Reflection,使用单独的事件处理类和适配器模式。

我看到在Java中使用函数指针/委托的最常见方法是使用函子。

基本上,使用单个方法定义接口并使用它的实例作为回调:

public interface Callback<T,V>{
  public T invoke(V context);
}

它比C / C ++或C#等价物更冗长,但它有效。标准库中此模式的一个示例是Comparator接口。

不幸的是,在Java中,函数不是第一类对象。您可以做的最好是使用界面:

public interface MyCallback
{
    public void theCallback(int arg);
}

public class Sample
{
    public static void takesACallback(MyCallback callback)
    {
        ...
        callback.theCallback(arg);
    }
}

public class Sample2
{
    public static void main(String[] args)
    {
        Sample.takesACallback(new MyCallback()
        {
            void theCallback(int arg)
            {
                // do a little dance
            }
        });
    }
}

一个非常常见的回调构造是Swing中的事件处理程序,其中ActionListeners可能是最容易掌握的。

查看 http://java.sun的.com /文档/书籍/教程/ uiswing /活动/ actionlistener.html

您经常提供实现适当接口的匿名类的实例,类似于

listener = new ActionListener() {
  public void actionPerformed(ActionEvent e) {
     // do stuff...
  }
};

然后将侦听器传递给适当的Swing方法。

我个人认为 Java 迫切需要某种形式的闭包支持。在此期间,我在 Java 中实现了基于反射的通用方法回调。它是 发布在我的网站上.

这种方法的好处是它的通用性。目的是能够编写像文件系统树遍历一样的 API,而不必每次都定义接口,而是使用 API 在代码中指定一个方法来执行工作。

例如,遍历文件系统树来处理每个文件:

进程目录树 API

/**
 * Process a directory using callbacks.  To interrupt, the callback must throw an (unchecked) exception.
 * Subdirectories are processed only if the selector is null or selects the directories, and are done
 * after the files in any given directory.  When the callback is invoked for a directory, the file
 * argument is null;
 * <p>
 * The callback signature is:
 * <pre>    void callback(File dir, File ent);</pre>
 * <p>
 * @return          The number of files processed.
 */
static public int processDirectory(File dir, Callback cbk, FileSelector sel) {
    return _processDirectory(dir,new Callback.WithParms(cbk,2),sel);
    }

static private int _processDirectory(File dir, Callback.WithParms cbk, FileSelector sel) {
    int                                 cnt=0;

    if(!dir.isDirectory()) {
        if(sel==null || sel.accept(dir)) { cbk.invoke(dir.getParent(),dir); cnt++; }
        }
    else {
        cbk.invoke(dir,(Object[])null);

        File[] lst=(sel==null ? dir.listFiles() : dir.listFiles(sel));
        if(lst!=null) {
            for(int xa=0; xa<lst.length; xa++) {
                File ent=lst[xa];
                if(!ent.isDirectory()) {
                    cbk.invoke(dir,ent);
                    lst[xa]=null;
                    cnt++;
                    }
                }
            for(int xa=0; xa<lst.length; xa++) {
                File ent=lst[xa];
                if(ent!=null) { cnt+=_processDirectory(ent,cbk,sel); }
                }
            }
        }
    return cnt;
    }

使用进程目录 API

通过编写上述方法,我现在可以非常轻松地处理目录树的任何操作;扫描、计数、列表等通过稍作更改,可以在文件/树删除等降序操作之前和之后调用目录上的回调(需要一个附加参数来指示调用的前/后性质)。

static private final Method             COUNT =Callback.getMethod(Xxx.class,"callback_count",true,File.class,File.class);

...

IoUtil.processDirectory(root,new Callback(this,COUNT),selector);

...

private void callback_count(File dir, File fil) {
    if(fil!=null) {                                                             // file is null for processing a directory
        fileTotal++;
        if(fil.length()>fileSizeLimit) {
            throw new Abort("Failed","File size exceeds maximum of "+TextUtil.formatNumber(fileSizeLimit)+" bytes: "+fil);
            }
        }
    progress("Counting",dir,fileTotal);
    }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top