Функции обратного вызова в Java - PullRequest
157 голосов
/ 14 января 2009

Есть ли способ передать функцию обратного вызова в методе Java?

Я пытаюсь имитировать поведение. Делегат .Net передается в функцию.

Я видел людей, предлагающих создать отдельный объект, но это кажется излишним, но я знаю, что иногда избыточное убийство - единственный способ сделать что-то

Ответы [ 17 ]

147 голосов
/ 14 января 2009

Если вы имеете в виду что-то вроде анонимного делегата .NET, я думаю, что анонимный класс 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));

    }
}
29 голосов
/ 06 ноября 2014

Начиная с Java 8, существуют ссылки на лямбду и методы:

Например, давайте определим:

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

и

import java.util.function.Function;

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

Тогда вы можете сделать:

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

Вы можете найти пример на github, здесь: julien-diener / MethodReference .

25 голосов
/ 13 декабря 2013

Для простоты вы можете использовать Runnable :

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

Использование:

runCallback(new Runnable()
{
    @Override
    public void run()
    {
        // Running callback
    }
});
16 голосов
/ 22 июня 2009

Немного придирки:

Мне кажется, люди предлагают создать отдельный объект, но это кажется излишество

Передача обратного вызова включает создание отдельного объекта практически на любом языке ОО, поэтому вряд ли это можно считать излишним. Вы, вероятно, имеете в виду, что в Java требуется создать отдельный класс, который является более подробным (и более ресурсоемким), чем в языках с явными первоклассными функциями или замыканиями. Тем не менее, анонимные классы, по крайней мере, уменьшают многословие и могут быть использованы встроенными.

12 голосов
/ 19 декабря 2017

все же я вижу, что есть наиболее предпочтительный способ, который был тем, что я искал ... он в основном получен из этих ответов, но мне пришлось манипулировать им, чтобы сделать его более более избыточным и эффективным. я придумаю

В точку ::

сначала создайте интерфейс так просто

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

теперь, чтобы запускать этот обратный вызов, когда вам захочется обработать результаты - более вероятно после асинхронного вызова, и вы захотите запустить некоторые вещи, которые зависят от этих повторных вызовов

// 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 - это функция, которая требует некоторого времени, когда вы хотите добавить к нему обратный вызов, чтобы уведомить вас о результатах, добавить интерфейс обратного вызова в качестве параметра к этому методу

надеюсь, моя точка зрения ясна, наслаждайтесь;)

7 голосов
/ 03 апреля 2017

Это очень просто в Java 8 с лямбдами.

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();
    }
}
7 голосов
/ 15 июля 2011

Мне показалась интересной идея использования библиотеки рефлексов, и я пришел к этому, который, я думаю, работает довольно хорошо. Единственным недостатком является потеря проверки времени компиляции, что вы передаете действительные параметры.

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

Вы используете это так

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);
        }
    }
}
5 голосов
/ 14 января 2009

Метод (пока) не является первоклассным объектом в Java; Вы не можете передать указатель на функцию в качестве обратного вызова. Вместо этого создайте объект (который обычно реализует интерфейс), содержащий необходимый метод, и передайте его.

Предложения по замыканиям в Java - которые обеспечили бы поведение, которое вы ищете - были сделаны, но ни одно из них не будет включено в предстоящий выпуск Java 7.

4 голосов
/ 14 января 2009

Когда мне нужны такие функции в Java, я обычно использую шаблон Observer . Это подразумевает дополнительный объект, но я думаю, что это чистый путь, и это широко понятный шаблон, который помогает с читабельностью кода.

4 голосов
/ 12 сентября 2009

Проверьте замыкания, как они были реализованы в библиотеке lambdaj. Они на самом деле ведут себя очень похоже на делегатов C #:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...