Reputation: 55760
Is there a way to pass a call back function in a Java method?
The behavior I'm trying to mimic is a .Net Delegate being passed to a function.
I've seen people suggesting creating a separate object but that seems overkill, however I am aware that sometimes overkill is the only way to do things.
Upvotes: 214
Views: 330181
Reputation: 15539
Since Java 8, there are lambda and method references:
For example, if you want a functional interface A -> B
, you can use:
import java.util.function.Function;
public class MyClass {
public static String applyFunction(Function<Integer,String> function){
return function.apply(42);
}
}
And here is how you can call it:
MyClass.applyFunction(value -> "the answer is: " + value);
// returns "the answer is: 42"
Also you can pass class method. For example:
@Value // lombok
public class PrefixAppender {
private String prefix;
public String addPrefix(Integer value){
return prefix + "=" + value;
}
}
Then you can do:
PrefixAppender prefixAppender= new PrefixAppender("6*9");
MyClass.applyFunction(prefixAppender::addPrefix);
// returns "6*9=42"
Note:
Here I used the functional interface Function<A,B>
, but there are many others in the package java.util.function
. Most notable ones are
Supplier
: void -> A
Consumer
: A -> void
BiConsumer
: (A,B) -> void
Function
: A -> B
BiFunction
: (A,B) -> C
and many others that specialize on some of the input/output type. Then, if it doesn't provide the one you need, you can create your own FunctionalInterface
:
@FunctionalInterface
interface Function3<In1, In2, In3, Out> { // (In1,In2,In3) -> Out
public Out apply(In1 in1, In2 in2, In3 in3);
}
Example of use:
String computeAnswer(Function3<String, Integer, Integer, String> f){
return f.apply("6x9=", 6, 9);
}
computeAnswer((question, a, b) -> question + "42");
// "6*9=42"
And you can also do that with thrown exception:
@FunctionalInterface
interface FallibleFunction<In, Out, Ex extends Exception> {
Out get(In input) throws Ex;
}
public <Ex extends IOException> String yo(FallibleFunction<Integer, String, Ex> f) throws Ex {
return f.get(42);
}
Upvotes: 79
Reputation: 1067
In JAVA, we can use a piece of executable code that can be called later, for example after a certain event or completion of a task(Callback Function). This is useful when we want to delay the execution or we need to handle asynchronous processes (as an example an async http-request, when the point is not blocking the main program flow because of waiting for one thread to finish running.
In JAVA, usually Callback Functions are implemented by Interface
.
In the following code, you see a simple calculator. I have defined an interface called "ResultListener" that contains a method. This method(onResult) is then implemented by another class or passed as a lambda expression
. The onResult method is like a placeholder for what should be done, when the result is available.
The "Calculator" class handles the arithmetic operations (Add, Subtract, Multiply and Division) using an ExecutorService
. These methods are called in a loop in Main function and for each call a task is submitted to the thread pool that is excecuted asynchronously.
Once the operation is completed, the onResult method of corresponding "ResultListener" (here instantiated by name: listener) is invoked passing the type of operation, variables (operands) and the result.
in the main function when we instantiate "ResultListener", the lambda expression is defining what should be done when the Callback
is invoked.
ResultListener listener = (operation, a, b, result) -> System.out.println(operation + " of " + a + ", " + b + " Result: " + result);
here, it is just printing.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class test {
public interface ResultListener {
void onResult(String operation ,int a, int b, int result);
}
public static class Calculator {
private ResultListener listener;
private ExecutorService executor = Executors.newFixedThreadPool(5);
public Calculator(ResultListener listener) {
this.listener = listener;
}
public void Add(int a, int b) {
executor.execute(() -> {
int resultAdd = a + b;
listener.onResult("Addition", a, b, resultAdd);
});
}
public void Subtract(int a , int b) {
executor.execute(()->{
int resultSub = a - b;
listener.onResult("Subtraction",a, b, resultSub);
});
}
public void Multiply(int a , int b) {
executor.execute(()->{
int resultMultiply = a * b;
listener.onResult("Multiplication",a, b, resultMultiply);
});
}
public void Divide(int a , int b) {
executor.execute(()->{
if(b!=0) {
int resultDiv = a / b;
listener.onResult("Division",a, b, resultDiv);
}else {
System.err.println("Error Happaned .. Illegal Division by 0");
}
});
}
public void shutdown() {
executor.shutdown();
}
}
public static void main(String[] args) {
ResultListener listener = (operation, a, b, result) -> System.out.println(operation + " of " + a + ", " + b + " Result: " + result);
Calculator cal = new Calculator(listener);
for(int i=10 , j = 1 ; j< 5; ++j , --i) {
cal.Add(i, j);
System.out.println("*************** Addition of "+ i +", " + j + " is being processed asynchronously.***************");
cal.Subtract(i, j);
System.out.println("*************** Subtract "+ i +", " + j + " is being processed asynchronously.***************");
cal.Multiply(i, j);
System.out.println("*************** Multiply "+ i +", " + j + " is being processed asynchronously.***************");
cal.Divide(i, j);
System.out.println("*************** Division "+ i +", " + j + " is being processed asynchronously.*************** ");
}
cal.shutdown();
}
the "ResultListener" acts as a callback that is called asynchronously with the results of arithmetic operations. The execution is shown in the photo:
Upvotes: 0
Reputation: 19139
For simplicity, you can use a Runnable:
private void runCallback(Runnable callback)
{
// Run callback
callback.run();
}
Usage:
runCallback(new Runnable()
{
@Override
public void run()
{
// Running callback
}
});
or with Java8 lambdas
runCallback(() -> {
// Running callback
});
Upvotes: 47
Reputation: 3246
with java 8 this task is kinda easy, if you want to use callback in multi-thread scenario you can do something similar like the following:
public void methodA (int n, IntConsumer consumer) {
// create a thread
Thread t = new Thread(() -> {
// some time consuming operation
int result = IntStream.range(0, n).sum();
// after the result is ready do something with it.
consumer.accept(result);
});
t.start();
}
and to use this method do:
methodA(1000000, System.out::println);
Upvotes: 2
Reputation: 435
Simpliest and easiest way is by creating a reusable model and trigger.... https://onecompiler.com/java/3wejrcby2?fbclid=IwAR0dHbGDChRUJoCZ3CIDW-JQu7Dz3iYGNGYjxYVCPCWfEqQDogFGTwuOuO8
Upvotes: 0
Reputation: 733
Create an Interface, and Create the Same Interface Property in Callback Class.
interface dataFetchDelegate {
void didFetchdata(String data);
}
//callback class
public class BackendManager{
public dataFetchDelegate Delegate;
public void getData() {
//Do something, Http calls/ Any other work
Delegate.didFetchdata("this is callbackdata");
}
}
Now in the class where you want to get called back implement the above Created Interface. and Also Pass "this" Object/Reference of your class to be called back.
public class Main implements dataFetchDelegate
{
public static void main( String[] args )
{
new Main().getDatafromBackend();
}
public void getDatafromBackend() {
BackendManager inc = new BackendManager();
//Pass this object as reference.in this Scenario this is Main Object
inc.Delegate = this;
//make call
inc.getData();
}
//This method is called after task/Code Completion
public void didFetchdata(String callbackData) {
// TODO Auto-generated method stub
System.out.println(callbackData);
}
}
Upvotes: 0
Reputation: 4615
yet i see there is most preferred way which was what i was looking for.. it's basically derived from these answers but i had to manipulate it to more more redundant and efficient.. and i think everybody looking for what i come up with
first make an Interface that simple
public interface myCallback {
void onSuccess();
void onError(String err);
}
now to make this callback run when ever you wish to do to handle the results - more likely after async call and you wanna run some stuff which depends on these reuslts
// import the Interface class here
public class App {
public static void main(String[] args) {
// call your method
doSomething("list your Params", new myCallback(){
@Override
public void onSuccess() {
// no errors
System.out.println("Done");
}
@Override
public void onError(String err) {
// error happen
System.out.println(err);
}
});
}
private void doSomething(String param, // some params..
myCallback callback) {
// now call onSuccess whenever you want if results are ready
if(results_success)
callback.onSuccess();
else
callback.onError(someError);
}
}
doSomething
is the function that takes some time you wanna add a callback to it to notify you when the results came, add the call back interface as a parameter to this method
Upvotes: 32
Reputation:
This is very easy in Java 8 with lambdas.
public interface Callback {
void callback();
}
public class Main {
public static void main(String[] args) {
methodThatExpectsACallback(() -> System.out.println("I am the callback."));
}
private static void methodThatExpectsACallback(Callback callback){
System.out.println("I am the method.");
callback.callback();
}
}
Upvotes: 15
Reputation: 893
You also can do theCallback
using the Delegate
pattern:
Callback.java
public interface Callback {
void onItemSelected(int position);
}
PagerActivity.java
public class PagerActivity implements Callback {
CustomPagerAdapter mPagerAdapter;
public PagerActivity() {
mPagerAdapter = new CustomPagerAdapter(this);
}
@Override
public void onItemSelected(int position) {
// Do something
System.out.println("Item " + postion + " selected")
}
}
CustomPagerAdapter.java
public class CustomPagerAdapter {
private static final int DEFAULT_POSITION = 1;
public CustomPagerAdapter(Callback callback) {
callback.onItemSelected(DEFAULT_POSITION);
}
}
Upvotes: 3
Reputation: 311
it's a bit old, but nevertheless... I found the answer of Peter Wilkinson nice except for the fact that it does not work for primitive types like int/Integer.
The problem is the .getClass()
for the parameters[i]
, which returns for instance java.lang.Integer
, which on the other hand will not be correctly interpreted by getMethod(methodName,parameters[])
(Java's fault) ...
I combined it with the suggestion of Daniel Spiewak (in his answer to this); steps to success included: catching NoSuchMethodException
-> getMethods()
-> looking for the matching one by method.getName()
-> and then explicitly looping through the list of parameters and applying Daniels solution, such identifying the type matches and the signature matches.
Upvotes: 1
Reputation: 1
public class HelloWorldAnonymousClasses {
//this is an interface with only one method
interface HelloWorld {
public void printSomething(String something);
}
//this is a simple function called from main()
public void sayHello() {
//this is an object with interface reference followed by the definition of the interface itself
new HelloWorld() {
public void printSomething(String something) {
System.out.println("Hello " + something);
}
}.printSomething("Abhi");
//imagine this as an object which is calling the function'printSomething()"
}
public static void main(String... args) {
HelloWorldAnonymousClasses myApp =
new HelloWorldAnonymousClasses();
myApp.sayHello();
}
}
//Output is "Hello Abhi"
Basically if you want to make the object of an interface it is not possible, because interface cannot have objects.
The option is to let some class implement the interface and then call that function using the object of that class. But this approach is really verbose.
Alternatively, write new HelloWorld() (*oberserve this is an interface not a class) and then follow it up with the defination of the interface methods itself. (*This defination is in reality the anonymous class). Then you get the object reference through which you can call the method itself.
Upvotes: 0
Reputation: 5229
I've recently started doing something like this:
public class Main {
@FunctionalInterface
public interface NotDotNetDelegate {
int doSomething(int a, int b);
}
public static void main(String[] args) {
// in java 8 (lambdas):
System.out.println(functionThatTakesDelegate((a, b) -> {return a*b;} , 10, 20));
}
public static int functionThatTakesDelegate(NotDotNetDelegate del, int a, int b) {
// ...
return del.doSomething(a, b);
}
}
Upvotes: 2
Reputation: 29889
If you mean somthing like .NET anonymous delegate, I think Java's anonymous class can be used as well.
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: 178
Reputation: 1624
I tried using java.lang.reflect to implement 'callback', here's a sample:
package StackOverflowQ443708_JavaCallBackTest;
import java.lang.reflect.*;
import java.util.concurrent.*;
class MyTimer
{
ExecutorService EXE =
//Executors.newCachedThreadPool ();
Executors.newSingleThreadExecutor ();
public static void PrintLine ()
{
System.out.println ("--------------------------------------------------------------------------------");
}
public void SetTimer (final int timeout, final Object obj, final String methodName, final Object... args)
{
SetTimer (timeout, obj, false, methodName, args);
}
public void SetTimer (final int timeout, final Object obj, final boolean isStatic, final String methodName, final Object... args)
{
Class<?>[] argTypes = null;
if (args != null)
{
argTypes = new Class<?> [args.length];
for (int i=0; i<args.length; i++)
{
argTypes[i] = args[i].getClass ();
}
}
SetTimer (timeout, obj, isStatic, methodName, argTypes, args);
}
public void SetTimer (final int timeout, final Object obj, final String methodName, final Class<?>[] argTypes, final Object... args)
{
SetTimer (timeout, obj, false, methodName, argTypes, args);
}
public void SetTimer (final int timeout, final Object obj, final boolean isStatic, final String methodName, final Class<?>[] argTypes, final Object... args)
{
EXE.execute (
new Runnable()
{
public void run ()
{
Class<?> c;
Method method;
try
{
if (isStatic) c = (Class<?>)obj;
else c = obj.getClass ();
System.out.println ("Wait for " + timeout + " seconds to invoke " + c.getSimpleName () + "::[" + methodName + "]");
TimeUnit.SECONDS.sleep (timeout);
System.out.println ();
System.out.println ("invoking " + c.getSimpleName () + "::[" + methodName + "]...");
PrintLine ();
method = c.getDeclaredMethod (methodName, argTypes);
method.invoke (obj, args);
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
PrintLine ();
}
}
}
);
}
public void ShutdownTimer ()
{
EXE.shutdown ();
}
}
public class CallBackTest
{
public void onUserTimeout ()
{
System.out.println ("onUserTimeout");
}
public void onTestEnd ()
{
System.out.println ("onTestEnd");
}
public void NullParameterTest (String sParam, int iParam)
{
System.out.println ("NullParameterTest: String parameter=" + sParam + ", int parameter=" + iParam);
}
public static void main (String[] args)
{
CallBackTest test = new CallBackTest ();
MyTimer timer = new MyTimer ();
timer.SetTimer ((int)(Math.random ()*10), test, "onUserTimeout");
timer.SetTimer ((int)(Math.random ()*10), test, "onTestEnd");
timer.SetTimer ((int)(Math.random ()*10), test, "A-Method-Which-Is-Not-Exists"); // java.lang.NoSuchMethodException
timer.SetTimer ((int)(Math.random ()*10), System.out, "println", "this is an argument of System.out.println() which is called by timer");
timer.SetTimer ((int)(Math.random ()*10), System.class, true, "currentTimeMillis");
timer.SetTimer ((int)(Math.random ()*10), System.class, true, "currentTimeMillis", "Should-Not-Pass-Arguments"); // java.lang.NoSuchMethodException
timer.SetTimer ((int)(Math.random ()*10), String.class, true, "format", "%d %X", 100, 200); // java.lang.NoSuchMethodException
timer.SetTimer ((int)(Math.random ()*10), String.class, true, "format", "%d %X", new Object[]{100, 200});
timer.SetTimer ((int)(Math.random ()*10), test, "NullParameterTest", new Class<?>[]{String.class, int.class}, null, 888);
timer.ShutdownTimer ();
}
}
Upvotes: 2
Reputation: 7461
I found the idea of implementing using the reflect library interesting and came up with this which I think works quite well. The only down side is losing the compile time check that you are passing valid parameters.
public class CallBack {
private String methodName;
private Object scope;
public CallBack(Object scope, String methodName) {
this.methodName = methodName;
this.scope = scope;
}
public Object invoke(Object... parameters) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
Method method = scope.getClass().getMethod(methodName, getParameterClasses(parameters));
return method.invoke(scope, parameters);
}
private Class[] getParameterClasses(Object... parameters) {
Class[] classes = new Class[parameters.length];
for (int i=0; i < classes.length; i++) {
classes[i] = parameters[i].getClass();
}
return classes;
}
}
You use it like this
public class CallBackTest {
@Test
public void testCallBack() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
TestClass testClass = new TestClass();
CallBack callBack = new CallBack(testClass, "hello");
callBack.invoke();
callBack.invoke("Fred");
}
public class TestClass {
public void hello() {
System.out.println("Hello World");
}
public void hello(String name) {
System.out.println("Hello " + name);
}
}
}
Upvotes: 7
Reputation: 13758
Check the closures how they have been implemented in the lambdaj library. They actually have a behavior very similar to C# delegates:
http://code.google.com/p/lambdaj/wiki/Closures
Upvotes: 4
Reputation: 346309
A little nitpicking:
I've seem people suggesting creating a separate object but that seems overkill
Passing a callback includes creating a separate object in pretty much any OO language, so it can hardly be considered overkill. What you probably mean is that in Java, it requires you to create a separate class, which is more verbose (and more resource-intensive) than in languages with explicit first-class functions or closures. However, anonymous classes at least reduce the verbosity and can be used inline.
Upvotes: 17
Reputation: 10283
When I need this kind of functionality in Java, I usually use the Observer pattern. It does imply an extra object, but I think it's a clean way to go, and is a widely understood pattern, which helps with code readability.
Upvotes: 4
Reputation: 269677
A method is not (yet) a first-class object in Java; you can't pass a function pointer as a callback. Instead, create an object (which usually implements an interface) that contains the method you need and pass that.
Proposals for closures in Java—which would provide the behavior you are looking for—have been made, but none will be included in the upcoming Java 7 release.
Upvotes: 5