Reputation: 1289
This question has two parts;
Part 1:
I'm not entirely clear on why a callback is needed, why not just pass in an object and call the method as seen in example code C, rather than creating an interface and then passing it in, like in example code A, or B.
Part 2:
What is the difference between the three example codes given bellow, is there a difference between A and B? Which one would be best in terms of performance and good practice, and why - i.e what is happening under the hood that causes the increase in performance, or why is it best to use one over another in terms of practicality.
example code A:
interface Iexample{
void foo();
}
public class Roo implements Iexample{
public void foo(){
System.out.println("hello");
}
}
public class Too{
public void eoo(Iexample callback){
callback.foo();
}
public static void main(String[] args){
Roo roo = new Roo();
Too too = new Too();
too.eoo(roo::foo);
}
}
example code B (only main is different):
interface Iexample{
void foo();
}
public class Roo implements Iexample{
public void foo(){
System.out.println("hello");
}
}
public class Too{
public void eoo(Iexample callback){
callback.foo();
}
public static void main(String[] args){
Roo roo = new Roo();
Too too = new Too();
too.eoo(roo);
}
}
example code C
public class Roo {
public void foo(){
System.out.println("hello");
}
}
public class Too{
public void eoo(Roo callback){
callback.foo();
}
public static void main(String[] args){
Roo roo = new Roo();
Too too = new Too();
too.eoo(roo);
}
}
edit: Anyone care to explain why you are downvoting? I'm happy to add more information if I knew what was wrong...
Upvotes: 1
Views: 7622
Reputation: 22079
In your example, you would not need a callback, but that depends on the intention of the code.
In terms of callbacks, what was probably meant in your code was the Command Pattern. Before Java 8, you could not pass functions as arguments, because function pointers as in C or C++ were not supported. A workaround is the command pattern, where you wrap a function call in a class and pass the class instead from which the corresponding function can be called. In your example, the interface Iexample
defines a wrapper for a method foo
without arguments or a return value.
Consider the following example. You have a main method that does show a GUI or something, while a background worker calculates something else. You have an output method where you want to show the current progress, but it is in your main class. Now, how would you pass the function to the worker, so it can use it? You use the command pattern and implement a wrapper class to carry the method like this:
interface ProgressCallback {
void progressUpdate(int progress);
}
class BackgroundWorker{
private int progress;
private ProgressCallback callback;
public BackgroundWorker(ProgressCallback progressCallback) {
this.callback = progressCallback;
}
// BackgroundWorker calls to signal the progress
// update to your main application, by calling
// its method passed through the callback wrapper
// class ProgressCallback.
private void notifyProgressUpdateToMain() {
callback.progressUpdate(progress);
}
// Awesome stuff implemented here
}
class Main {
public static void main(String[] args) {
// Implement a new callback "on-the-fly" with the interface
// as template for a progress callback.
ProgressUpdate callback = new ProgressUpdate(int progress) {
@Override
public void progressUpdate() {
// The call of the method of this main class
// is now encapsulated in the callback
setProgressUpdate(progress);
}
};
// Does awesome stuff in background
BackgroundWorker worker = new BackgroudWorker(callback);
worker.start();
// Do other stuff, while the worker sets the progress
}
private setProgressUpdate(int progress) {
// Magically retrieved progress bar from the GUI
progressBar.setProgress(progress);
}
}
Your first example just uses a new Java 8 operator ::
to pass the method foo()
as a parameter by creating an anonymous wrapper class. The second example can be used with earlier versions. The interface allows you to implement different callbacks easily, as seen in the example above. The third example cannot provide this flexibility, as you can only implement a single class Roo
and could only subclass it, which does not fit what you want to achieve here.
Upvotes: 1
Reputation: 31689
Note that in example A, your Roo
class doesn't have to implement Iexample
, and it doesn't have to call its method foo
. You can pass any method to eoo
as long as it is a void method with no parameters. Adding implements Iexample
to the code in this case probably obscures the issue, since the fact that it implements the interface isn't really used in your code.
The choice between A and B (and C) is mainly conceptual--i.e. what are you trying to convey? This is something that's hard to see when you have classes and methods with meaningless names. Defining an interface, and classes that implement that interface, is similar to extending an abstract class. You're defining an abstract base class, and saying that anything that implements that class will provide concrete implementations for one or more methods. Basically, you're defining an "is-a" relationship between classes.
Using a callback would be more appropriate when you just want a way to write a method that takes some other method as a parameter, without wanting to define any class relationships. For example, suppose I wanted to write a function that does a generalized Ʃ in math--that is, sum the values of some function for some index in a given range. My function would need to take some other function as a parameter, i.e. the thing I want to sum, which would take an int
as a parameter and return, say, a double
. But there wouldn't be any new classes involved--I just want it to take an arbitrary function. That's the case where you'd want to use a functional interface and a callback.
Note that in your example A, the method
public void eoo(Iexample callback){
must have, as a parameter, an object that implements Iexample
. But when you call it with
too.eoo(roo::foo);
the object that gets passed is not an object of class Roo
, but rather an anonymous class specially created by the compiler just to pass roo::foo
.
Upvotes: 1