Programming in language: what is the most elegant way to define callbacks in Java?

In the book "Code Complete", the author talks about programming in a language (instead of programming in a language). It means that you should not limit yourself to the limitations of your chosen programming language.

Callback is often used. I am wondering: what is the most elegant way to program callbacks in a Java language?

+4
source share
6 answers

Check out this article:

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

Callbacks are essentially a special case of od Delegates (as C # has), and the article provides an implementation of something that looks like a C # delegate in java.

+1
source

Java uses all kinds of callbacks for all kinds of situations. Ever since the oldest older AWT listeners, Java has been all about callbacks.

There are two main “flavors” of Java response requests. The first is the implementation of the interface:

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

The second taste of Java callback is an anonymous inner class:

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

There are other ways, including using Reflection, using separate event handling classes, and an adapter template.

+6
source

The most common way to deal with missing function / delegate pointers in Java is to use functors.

Basically, define the interface with one method and use it as a callback:

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

Its a lot more verbose than the equivalents of C / C ++ or C #, but it works. An example of this template in the standard library is the comparator interface.

+4
source

Unfortunately, in Java, functions are not first-class objects. The best you can do is use the interface:

 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 } }); } } 
+2
source

A very common callback construct is the event handlers in Swing, where ActionListeners are probably the easiest to understand.

Take a look at http://java.sun.com/docs/books/tutorial/uiswing/events/actionlistener.html

You very often provide an instance of an anonymous class that implements an appropriate interface similar to

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

where you pass the appropriate Swing method to the listener.

0
source

I personally feel that Java is desperate for some support for closing. In the meantime, I implemented a general method callback in Java. It is posted on my website .

The advantage of this approach is its versatility. The goal was to write an API like a file system tree, without having to define an interface each time, instead assigning a method in the code using the API to do the job.

For example, moving the file system tree to process each file:

Process Directory Tree 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; } 

Using the process catalog API

Using the method described above, I can now very easily process the directory tree for any operation; scanning, counting, listing, etc. With minor changes to call a callback in the directory, both before and after downstream operations, it was also possible to delete the file / tree (an additional parameter is required to indicate the background of the call message).

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

All Articles