Java中的回调函数
有没有一种方法可以在Java方法中传递回调函数 我试图模仿的行为是将.Net委托传递给函数Java中的回调函数,java,callback,function-pointers,Java,Callback,Function Pointers,有没有一种方法可以在Java方法中传递回调函数 我试图模仿的行为是将.Net委托传递给函数 我见过有人建议创建一个单独的对象,但这似乎有些过头了,不过我知道有时候过头了是做事情的唯一方法。如果你指的是.NET匿名委托之类的东西,我认为Java的匿名类也可以使用 public class Main { public interface Visitor{ int doJob(int a, int b); } public static void main
我见过有人建议创建一个单独的对象,但这似乎有些过头了,不过我知道有时候过头了是做事情的唯一方法。如果你指的是.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));
}
}
方法在Java中还不是一级对象;不能将函数指针作为回调传递。相反,创建一个包含所需方法的对象(通常实现一个接口)并传递它
已经提出了在Java中使用闭包的建议,这些闭包将提供您正在寻找的行为,但在即将发布的Java 7版本中不会包含任何闭包。当我需要Java中的此类功能时,我通常使用。它确实意味着一个额外的对象,但我认为这是一种干净的方式,是一种被广泛理解的模式,有助于提高代码的可读性。有点吹毛求疵: 我似乎有人建议创建一个 分开的对象,但似乎 滥杀
传递回调包括在几乎任何OO语言中创建一个单独的对象,因此这很难被认为是过分的。您可能的意思是,在Java中,它要求您创建一个单独的类,这比使用显式第一类函数或闭包的语言更冗长(而且资源更密集)。但是,匿名类至少可以减少冗长,并且可以内联使用。检查闭包是如何在lambdaj库中实现的。实际上,它们的行为与C#delegate非常相似:
我尝试使用java.lang.reflect实现“回调”,下面是一个示例:
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 ();
}
}
package StackOverflowQ443708_JavaCallBackTest;
导入java.lang.reflect.*;
导入java.util.concurrent.*;
类MyTimer
{
ExecutorService EXE=
//Executors.newCachedThreadPool();
Executors.newSingleThreadExecutor();
公共静态无效打印行()
{
System.out.println(“------------------------------------------------------------------------------------------------”;
}
public void SetTimer(最终int超时、最终对象obj、最终字符串methodName、最终对象…args)
{
SetTimer(超时、obj、false、methodName、args);
}
public void SetTimer(最终int超时、最终对象obj、最终布尔值isStatic、最终字符串methodName、最终对象…args)
{
类[]argTypes=null;
如果(args!=null)
{
argTypes=新类[args.length];
对于(int i=0;i[]argTypes,final Object…args)
{
EXE.execute(
新的Runnable()
{
公开作废运行()
{
丙级;;
方法;
尝试
{
如果(isStatic)c=(Class)obj;
else c=obj.getClass();
System.out.println(“等待“+超时+”秒以调用“+c.getSimpleName()+”:[“+methodName+”]”);
TimeUnit.SECONDS.sleep(超时);
System.out.println();
System.out.println(“调用”+c.getSimpleName()+“::[“+methodName+”]…”;
PrintLine();
method=c.getDeclaredMethod(methodName,argTypes);
方法调用(obj,args);
}
捕获(例外e)
{
e、 printStackTrace();
}
最后
{
PrintLine();
}
}
}
);
}
公共无效关闭计时器()
{
EXE.shutdown();
}
}
公共类回调测试
{
public void onUserTimeout()
{
System.out.println(“onUserTimeout”);
}
公共void onTestEnd()
{
System.out.println(“onTestEnd”);
}
public void NullParameterTest(字符串sParam,int-ipram)
{
System.out.println(“NullParameterTest:String parameter=“+sParam+”,int parameter=“+iParam”);
}
公共静态void main(字符串[]args)
{
CallBackTest=newcallbacktest();
MyTimer=newmytimer();
timer.SetTimer((int)(Math.random()*10),测试“onUserTimeout”);
timer.SetTimer((int)(Math.random()*10),测试“onTestEnd”);
timer.SetTimer((int)(Math.random()*10),测试“A-Method-Which-Is-Not-Exists”);//java.lang.NoSuchMethodException
timer.SetTimer((int)(Math.random()*10),System.out,“println”,“这是timer调用的System.out.println()的一个参数”);
timer.SetTimer((int)(Math.random()*10),System.class,true,“currentTimeMillis”);
timer.SetTimer((int)(Math.random()*10),System.class,true,“currentTimeMillis”,“不应传递参数”);//java.lang.NoSuchMethodException
timer.SetTimer((int)(Math.random()*10),String.class,true,“format”,“%d%X”,100200);//java.lang.NoSuchMethodException
timer.SetTimer((int)(Math.random()*10)、String.class、true、“格式”、“%d%X”、新对象[]{100200});
timer.SetTimer((int)(Math.random()*10),test,“NullParameterTest”,新类[]{String.Class,int.Class},null,888);
timer.ShutdownTimer();
}
}
我发现使用reflect库实现的想法很有趣,并提出了这个想法,我认为它非常有效。唯一的缺点是丢失了编译时检查,即您正在传递有效参数
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;
}
}
它有点老了,但无论如何……我找到了Peter Wilkinson nice的答案,除了它不适用于int/Integer之类的基本类型。 问题在于
.getClass
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);
}
}
}
private void runCallback(Runnable callback)
{
// Run callback
callback.run();
}
runCallback(new Runnable()
{
@Override
public void run()
{
// Running callback
}
});
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"
@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);
}
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"
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);
}
}
public interface Callback {
void onItemSelected(int position);
}
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")
}
}
public class CustomPagerAdapter {
private static final int DEFAULT_POSITION = 1;
public CustomPagerAdapter(Callback callback) {
callback.onItemSelected(DEFAULT_POSITION);
}
}
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();
}
}
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");
}
}
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);
}
}
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();
}
methodA(1000000, System.out::println);