pass parameter ejemplo java callback function-pointers

parameter - callback java ejemplo



Funciones de devoluciĆ³n de llamada en Java (16)

Compruebe los cierres cómo se han implementado en la biblioteca lambdaj. De hecho, tienen un comportamiento muy similar al de los delegados de C #:

http://code.google.com/p/lambdaj/wiki/Closures

¿Hay alguna manera de pasar una función de devolución de llamada en un método Java?

El comportamiento que intento imitar es que un delegado .Net sea pasado a una función.

He visto a personas sugiriendo crear un objeto por separado, pero eso parece exagerado, sin embargo, soy consciente de que a veces el exceso es la única forma de hacer las cosas.


Creo que usar una clase abstracta es más elegante, así:

// Something.java public abstract class Something { public abstract void test(); public void usingCallback() { System.out.println("This is before callback method"); test(); System.out.println("This is after callback method"); } } // CallbackTest.java public class CallbackTest extends Something { @Override public void test() { System.out.println("This is inside CallbackTest!"); } public static void main(String[] args) { CallbackTest myTest = new CallbackTest(); myTest.usingCallback(); } } /* Output: This is before callback method This is inside CallbackTest! This is after callback method */


Cuando necesito este tipo de funcionalidad en Java, suelo usar el patrón Observer . Implica un objeto adicional, pero creo que es una forma limpia de hacerlo, y es un patrón ampliamente entendido, que ayuda con la legibilidad del código.


Desde Java 8, hay referencias de lambda y método:

Por ejemplo, permite definir:

public class FirstClass { String prefix; public FirstClass(String prefix){ this.prefix = prefix; } public String addPrefix(String suffix){ return prefix +":"+suffix; } }

y

import java.util.function.Function; public class SecondClass { public String applyFunction(String name, Function<String,String> function){ return function.apply(name); } }

Entonces puedes hacer:

FirstClass first = new FirstClass("first"); SecondClass second = new SecondClass(); System.out.println(second.applyFunction("second",first::addPrefix));

Puede encontrar un ejemplo en github, aquí: julien-diener/MethodReference .


Encontré interesante la idea de implementar el uso de la biblioteca de reflejos y se me ocurrió esto, que creo que funciona bastante bien. El único inconveniente es perder la comprobación de tiempo de compilación de que está pasando parámetros válidos.

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

Lo usas así

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


Esto es muy fácil en Java 8 con 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(); } }


Intenté usar java.lang.reflect para implementar ''callback'', aquí hay una muestra:

package Q443708_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 (); } }


Para simplificar, puede usar un Runnable :

private void runCallback(Runnable callback) { // Run callback callback.run(); }

Uso:

runCallback(new Runnable() { @Override public void run() { // Running callback } });


Recientemente comencé a hacer algo como esto:

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


Si te refieres a algo así como un delegado anónimo de .NET, creo que también se puede usar la clase anónima de Java.

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


También puede hacer la Callback utilizando el patrón Delegate :

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


Un método no es (todavía) un objeto de primera clase en Java; no puede pasar un puntero a la función como devolución de llamada. En su lugar, cree un objeto (que generalmente implementa una interfaz) que contenga el método que necesita y pase eso.

Se han realizado propuestas para cierres en Java, que proporcionarían el comportamiento que está buscando, pero ninguna se incluirá en la próxima versión de Java 7.


Un poco de nitpicking:

Parece que la gente sugiere crear un objeto por separado, pero eso parece excesivo

Pasar una devolución de llamada incluye la creación de un objeto separado en casi cualquier idioma OO, por lo que difícilmente puede considerarse exagerado. Lo que probablemente quiera decir es que en Java, se requiere que cree una clase separada, que es más detallada (y requiere más recursos) que en los lenguajes con funciones o cierres explícitos de primera clase. Sin embargo, las clases anónimas al menos reducen la verbosidad y se pueden usar en línea.


es un poco viejo, pero sin embargo ... encontré la respuesta de Peter Wilkinson agradable, excepto por el hecho de que no funciona para tipos primitivos como int / Integer. El problema es el .getClass() para los parameters[i] , que devuelve, por ejemplo, java.lang.Integer , que por otro lado no será interpretado correctamente por getMethod(methodName,parameters[]) (error de Java). .

Lo combiné con la sugerencia de Daniel Spiewak ( en su respuesta a esto ); pasos para el éxito incluidos: capturando NoSuchMethodException -> getMethods() -> buscando la coincidencia por method.getName() -> y luego method.getName() explícitamente a través de la lista de parámetros y aplicando la solución de Daniels, identificando el tipo de coincidencias y las coincidencias de firmas .


sin embargo, veo que hay una forma más preferida que busqué, que básicamente se deriva de estas respuestas, pero tuve que manipularla para que fuera más redundante y eficiente ... y creo que todo el mundo busca lo que se me ocurre

Al punto::

primero haga una interfaz tan simple

public interface myCallback { void onSuccess(); void onError(String err); }

ahora para hacer que esta devolución de llamada se ejecute cuando lo desee para manejar los resultados, más probable después de la llamada asincrónica y desea ejecutar algunas cosas que dependen de estos reintentos

// 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 es la función que tarda un tiempo en agregarse una devolución de llamada para avisarle cuando llegaron los resultados, agregar la interfaz de devolución de llamada como parámetro para este método

Espero que mi punto sea claro, disfruta;)


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"

Básicamente, si desea hacer el objeto de una interfaz no es posible, porque la interfaz no puede tener objetos.

La opción es permitir que una clase implemente la interfaz y luego llamar a esa función usando el objeto de esa clase. Pero este enfoque es muy detallado.

Alternativamente, escriba HelloWorld () (* oberserve this es una interfaz no una clase) y luego siga con la definación de los métodos de interfaz en sí. (* Esta definición es en realidad la clase anónima). Luego obtienes la referencia del objeto a través del cual puedes llamar al método en sí.