Frage

Gibt es eine Möglichkeit, einen Rückruf-Funktion in einer Java-Methode übergeben?

Das Verhalten Ich versuche, eine Funktion zu imitieren ist bestanden, ein .NET-Delegierter wird.

Ich habe darauf hindeutet, gesehen, wie Menschen ein eigenes Objekt zu schaffen, aber das scheint übertrieben, aber ich weiß, dass manchmal viel des Guten ist der einzige Weg, Dinge zu tun.

War es hilfreich?

Lösung

Wenn Sie somthing wie .NET anonyme Delegaten meinen, ich denke, Java anonyme Klasse kann auch verwendet werden.

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

    }
}

Andere Tipps

Da Java 8 gibt es Lambda und Verfahren Referenzen:

Zum Beispiel kann definiert werden:

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

und

import java.util.function.Function;

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

Dann können Sie tun:

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

Sie können ein Beispiel auf Github, finden Sie hier:. julien-diener / MethodReference

Der Einfachheit halber können Sie verwenden ein Runnable :

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

Verbrauch:

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

Ein wenig Erbsenzählerei:

  

Ich habe die Leute scheinen darauf hindeutet, eine zu schaffen   separates Objekt, aber das scheint   Overkill

einen Rückruf Passing enthält in so ziemlich jede OO-Sprache ein eigenes Objekt zu schaffen, so kann es kaum übertrieben angesehen werden. Was Sie wahrscheinlich bedeuten, dass in Java, es erfordert, dass Sie eine eigene Klasse zu erstellen, die ausführlichere (und ressourcenintensiver) als in Sprachen mit expliziten First-Class-Funktionen oder Schließungen. Allerdings anonyme Klassen zumindest die Ausführlichkeit reduzieren und kann inline verwendet werden.

doch ich sehe es am meisten bevorzugter Weg ist, das war, was ich gesucht habe .. es im Grunde aus diesen Antworten abgeleitet ist, aber ich hatte es zu manipulieren, um mehr mehr redundant und effizient .. , und ich denke, jeder der Suche nach was i kommen mit

Auf den Punkt ::

zunächst eine Schnittstelle machen so einfach

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

nun diesen Rückruf laufen zu lassen, wann immer Sie wollen, um die Ergebnisse zu handhaben tun - eher nach async Anruf und Sie wollen ein paar Sachen laufen, die auf dieser reuslts hängt

// 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 ist die Funktion, die einige Zeit hinführt möchte hinzufügen, einen Rückruf, um es Ihnen zu benachrichtigen, wenn die Ergebnisse kamen, fügen Schnittstelle als Parameter an diese Methode den Anruf zurück

hoffe, mein Punkt klar ist, genießen;)

Dies ist sehr einfach in Java 8 mit Lambda-Ausdrücke.

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

Ich fand die Idee der Umsetzung der Bibliothek interessant und kam mit dieser reflektieren verwendet, die ich funktionieren recht gut denken. Der einzige Nachteil ist, verlieren die Kompilierung Prüfung, die Sie gültige Parameter übergeben.

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

Sie verwenden es wie folgt

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

Eine Methode ist (noch) nicht ein erstklassiges Objekt in Java; Sie können nicht einen Funktionszeiger als Rückruf übergeben. Erstellen Sie stattdessen ein Objekt (die in der Regel eine Schnittstelle implementiert), die die Methode enthält, die Sie brauchen, und dass übergeben.

Vorschläge für Verschlüsse in Java-die das Verhalten liefern würden Sie suchen-gemacht worden, aber keiner wird in der kommenden Java 7 Version enthalten sein.

Wenn ich diese Art von Funktionalität in Java benötigen, verwende ich in der Regel die Observer Muster rel="nofollow. Es tut ein zusätzliches Objekt bedeuten, aber ich denke, es ist ein sauberer Weg zu gehen, und ist ein weithin verstanden Muster, die mit der Lesbarkeit des Codes hilft.

die Verschlüsse prüfen, wie sie in der lambdaj Bibliothek umgesetzt wurden. Sie haben tatsächlich ein Verhalten sehr ähnlich zu C # Delegierten:

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

Ich habe versucht java.lang.reflect mit ‚Rückruf‘ zu implementieren, ist hier ein Beispiel:

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

Sie können auch tun theCallback das Delegate Muster mit:

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

Ich habe vor kurzem begonnen, so etwas wie dies zu tun:

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

es ist ein bisschen alt, aber dennoch ... fand ich die Antwort von Peter Wilkinson schön mit Ausnahme der Tatsache, dass es nicht für primitive Typen wie int / Integer funktioniert. Das Problem ist die .getClass() für die parameters[i], die beispielsweise java.lang.Integer zurückgibt, die auf der anderen Seite wird nicht korrekt von getMethod(methodName,parameters[]) interpretiert werden (Java-Fehler) ...

I kombiniert es mit dem Vorschlag von Daniel Spiewak ( auf diese in seiner Antwort); Schritte zum Erfolg enthielten: Fang NoSuchMethodException -> getMethods() -> für die Anpassung eines von method.getName() suchen -> und dann durch die Liste der Parameter explizit Looping und Daniels Lösung anwenden, wie die Art Spiele und die Signatur übereinstimmt Identifizierung

.

Ich denke, mit eine abstrakte Klasse ist eleganter, wie folgt aus:

// 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
*/
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"

Im Grunde genommen, wenn Sie die Aufgabe einer Schnittstelle zu machen, ist es nicht möglich, da Interface-Objekte nicht haben kann.

Die Option ist einige Klasse implementieren die Schnittstelle zu lassen und dann diese Funktion aufrufen, um das Objekt dieser Klasse. Aber dieser Ansatz ist wirklich ausführlich.

Alternativ schreiben neue Helloworld () (* oberserve dies eine Schnittstelle ist keine Klasse) und dann mit dem defination der Interface-Methoden selbst verfolgen. (* Diese defination ist in Wirklichkeit die anonyme Klasse). Dann Sie den Objektverweis erhalten, durch die Sie die Methode aufrufen selbst.

Erstellen Sie eine Schnittstelle, und erstellen die gleiche Schnittstelle Property in Callback-Klasse.

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

}

in der Klasse Jetzt, wo Sie die oben erstellte Schnittstelle genannt implementieren lassen wollen zurück. und auch Pass „die“ Objekt / Referenz Ihrer Klasse zurückgerufen werden.

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);
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top