是否有一种方法可以在Java方法中传递回调函数?

我试图模拟的行为是一个。net委托被传递给一个函数。

我看到有人建议创建一个单独的对象,但这似乎有点过分,但我意识到有时过度是做事的唯一方法。


当前回答

我发现使用反射库实现的想法很有趣,并提出了这个,我认为它工作得很好。唯一的缺点是丢失了传递有效参数的编译时检查。

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

其他回答

从Java 8开始,有lambda和方法引用:

Oracle文档:Lambda表达式 Oracle文档:方法引用

例如,如果你想要一个功能接口a -> B,你可以使用:

import java.util.function.Function;

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

你可以这样称呼它:

MyClass.applyFunction("42", str -> "the answer is: " + str);
// returns "the answer is: 42"

你也可以通过类方法。例如:

@Value // lombok
public class PrefixAppender {
    private String prefix;

    public String addPrefix(String suffix){
        return prefix +":"+suffix;
    }
}

然后你可以这样做:

PrefixAppender prefixAppender= new PrefixAppender("prefix");
MyClass.applyFunction("some text", prefixAppender::addPrefix);
// returns "prefix:some text"

注意:

这里我使用了函数接口Function<A,B>,但是包java.util.function中还有许多其他的接口。最值得注意的是

供应商:void -> 消费者:A ->无效 双消费者:(A,B) ->无效 功能:A -> B biffunction:(A,B) -> C

以及许多其他专门研究某些输入/输出类型的程序。然后,如果它不提供你需要的,你可以创建自己的FunctionalInterface:

@FunctionalInterface
interface Function3<In1, In2, In3, Out> { // (In1,In2,In3) -> Out
    public Out apply(In1 in1, In2 in2, In3 in3);
}

使用示例:

String computeAnswer(Function3<String, Integer, Integer, String> f){
    return f.apply("6x9=", 6, 9);
}

computeAnswer((question, a, b) -> question + "42");
// "6*9=42"

你也可以用抛出异常来实现:

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

有点吹毛求疵:

我听到有人建议创建一个 分开的物体,但看起来 过度

传递回调包括在几乎所有的OO语言中创建一个单独的对象,所以它几乎不能被认为是多余的。您的意思可能是,在Java中,它要求您创建一个单独的类,这比具有显式的一级函数或闭包的语言更冗长(也更消耗资源)。然而,匿名类至少减少了冗长,并且可以内联使用。

你也可以使用委托模式进行回调:

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

我最近开始做这样的事情:

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

如果你指的是。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));

    }
}