Reputation: 38899
I came across this question about callbacks in Java. Hers is the running code and original answer here.
Code:
public class Main {
public interface Visitor {
int DoJob(int a, int b);
}
public static void main(String[] args) {
Visitor adder = new Visitor(){
public int DoJob(int a, int b) {
return a + b;
}
};
Visitor multiplier = new Visitor(){
public int DoJob(int a, int b) {
return a*b;
}
};
System.out.println(adder.DoJob(10, 20));
System.out.println(multiplier.DoJob(10, 20));
}
}
Upvotes: 6
Views: 11901
Reputation: 15624
I used to develop in Java and I did not fully understand the callback concept until I began programming with C# and its delegates.
The reason of that is because as @Denilson Sá perfectly mentioned Java does not use pointers to functions. In other words, in Java you can call a method and pass some arguments such as primitive values (int, long, char, boolean, etc.) and objects (String or any instance of any class as when you passs an object you are basically passing the address in memory of the real object that lives somewhere in memory).
The callback concept in Java could be implemented by using interfaces and passing them (the object that implements them) as arguments. Imagine you have the following interface that defines 2 methods that ANY class that wants to behave as a ResultListener must implement.
interface ResultListener {
void onSuccessOperation(String description);
void onFailedOperation(String description);
}
Now imagine you have a main program that is running inside the showScreen method
class MyMainScreen implements ResultListener {
public void showScreen() {
//do some things..
SmartClass smartClass = new SmartClass();
smartClass.divideAndNotify(5, 0, this);
}
public void onSuccessOperation(String description) {
System.out.println("SUCCESS!!. " + description);
}
public void onFailedOperation(String description) {
System.out.println("FAILED. " + description);
}
}
And this is the SmartClass that knows how to divide.
class SmartClass {
public void divideAndNotify(int numerador, int denominador, ResultListener resultListener) {
if (denominador == 0) {
resultListener.onFailedOperation("Nobody can divide by zero!!");
} else {
int total = numerador / denominador;
resultListener.onSuccessOperation("The result is " + total);
}
}
}
The interesting part here is that MyMainScreen is behaving as a ResultListener so it needs to implement the methods defined in the interface ResultListener. MyMainScreen knows how to print messages on console, but it does not know anything about calculations, and that is why it instantiates the SmartClass to use its method divideAndNotify that accepts 2 numbers and a reference to the instance that will listen to the result (in our case this instance is the MyMainScreen instance itself, and that's why it passes itself with the word this)
The SmartClass method divideAndNotify knows maths and will notify whoever is listening with the result of the operation. Its method knows that resultListener will contain the reference to an object that knows what to do when the result is successful or unsuccessful.
The callback concept here is that SmartClass is delegating the functionality on what to do with the result, it is like "calling back" something in the instance that it received as a parameter.
As a summary: A callback is simply a DELEGATION of a task.
PS: With C# this concept is much more straightforward because C# has delegate types that are variables that store addresses of memory where functions reside (the functions that store must match the signature defined in the delegate).
Upvotes: 3
Reputation: 49347
I don't want to start a flame war here... But the concept of callbacks is a lot easier to understand in languages like C/C++, JavaScript, Python, probably Ruby and many others. In such languages, a callback is just a function pointer. You pass your function as this function pointer, and the other code will call back your function using that pointer. As simple as that. (look at this C example from Wikipedia)
But Java does not have function pointers, and thus the Java programmer is required to use Anonymous Inner Classes, Interfaces and things like that in order to encapsulate a function inside a class, and pass an instance of that class as the callback.
I think I managed to answer your second question ("Can you explain the concept of callback to a Java programmer?"), but please see the other answers about how to implement that in Java.
Upvotes: 4
Reputation: 4089
They are called "Anonymous Inner Classes". They are basically an implementation of an interface/abstract class without having to write a fully blown class.
The compiler will actually create a class for each one of these, so if you compile the above code, you'll see something like:
Main.class
Main$Visitor.class
Main$1.class <-- This is probably the "adder" implementation
Main$2.class <-- This is probably the "multiplier" implementation
The beauty of these classes is that they can read stuff from your method/class without you having to pass those parameters. For instance:
...
final int extraMultiplyer = 10;
Visitor multiplier = new Visitor(){
public int DoJob(int a, int b) {
//Note that extraMultiplyer is defined in the main() method
//and is final.
return a*b*extraMultiplyer;
}
};
...
They are particularly useful for event handling (think Swing), where you usually need to implement the ActionListener interface where you need to have a actionPerormed() method. If you have a UI class with many different controls, whenever you register the listeners, you might want to register these annonymous classes to: a) make the code (arguably) more readable and b) to make it easier to know what each component does, instead of having a giant "if-else if-else" style actionPerfomed implementation
for instance:
//abbreviated code
button1.addActionListener(new ActionListener(){
//you do what you need here for the action of pressing this button
});
button2.addActionListener(new ActionListener() {
//you do what you need here for the action of pressing this button
});
Upvotes: 1
Reputation: 1219
I wrote a small blog post on this sometime back : http://madhurtanwani.blogspot.com/2010/09/callbacks-in-java.html. Hope it helps!
Before I try explaining the above code post, I must say, its not the most intuitive or good use of call backs. The example I've used in my post is of Collections.sort() which clearly brings out the callback part.
Neverthelss, for the code posted above, think of like this :
doJob
method on a Visitor
interface
implementations, whenever I receive a pair of data sets. What the caller must do is implement the Visitor interface and implement the domain specific logic to process the datasets.The part of delegating processing from the caller, back to the callee is called a callback implemented using interface
(contract specification) in Java.
Upvotes: 6
Reputation: 2545
You're talking about an entity I never called callbacks myself. The entities your are talking about are called function pointers (as mentioned by madhuranwani) / delegates / anonymous functions / actions.
These ones are usually used for customization of generic algorithm implementations (such as Collections.sort, as you mentioned).
public class Actions {
public static void main(String[] args) {
printingAlgorithm(new Action() {
public void perform() {
System.out.println("CustomAction.perform");
}
});
}
private static void printingAlgorithm(Action customization) {
System.out.println("------");
customization.perform();
System.out.println("++++++");
}
}
interface Action {
void perform();
}
Entity which are usually called callbacks in my area act more like listeners. Here is an example:
public class Callbacks {
public static void main(String[] args) {
printingAlgorithm(new PrintingCallback() {
public void printBody() {
System.out.println("custom body");
}
public void printHeader() {
System.out.println("---------");
}
public void printFooter() {
System.out.println("+++++++++");
}
});
}
private static void printingAlgorithm(PrintingCallback callback) {
callback.printHeader();
callback.printBody();
callback.printFooter();
}
}
interface PrintingCallback {
void printHeader();
void printBody();
void printFooter();
}
Upvotes: 0