我正在寻找一种通过引用传递方法的方法。我知道Java不传递方法作为参数,但是,我想要一个替代方案。
我被告知接口是作为参数传递方法的替代方案,但我不理解接口如何通过引用充当方法。如果我理解正确的话,接口只是一组没有定义的抽象方法。我不想发送一个每次都需要定义的接口,因为几个不同的方法可以用相同的参数调用相同的方法。
我想要完成的是类似这样的事情:
public void setAllComponents(Component[] myComponentArray, Method myMethod) {
for (Component leaf : myComponentArray) {
if (leaf instanceof Container) { //recursive call if Container
Container node = (Container) leaf;
setAllComponents(node.getComponents(), myMethod);
} //end if node
myMethod(leaf);
} //end looping through components
}
调用方法如下:
setAllComponents(this.getComponents(), changeColor());
setAllComponents(this.getComponents(), changeSize());
我很欣赏上面的答案,但我可以使用下面的方法实现相同的行为;这个想法借鉴自Javascript的回调。我对修正持开放态度,尽管到目前为止(在生产中)还不错。
其思想是在签名中使用函数的返回类型,这意味着yield必须是静态的。
下面是一个运行带有超时的进程的函数。
public static void timeoutFunction(String fnReturnVal) {
Object p = null; // whatever object you need here
String threadSleeptime = null;
Config config;
try {
config = ConfigReader.getConfigProperties();
threadSleeptime = config.getThreadSleepTime();
} catch (Exception e) {
log.error(e);
log.error("");
log.error("Defaulting thread sleep time to 105000 miliseconds.");
log.error("");
threadSleeptime = "100000";
}
ExecutorService executor = Executors.newCachedThreadPool();
Callable<Object> task = new Callable<Object>() {
public Object call() {
// Do job here using --- fnReturnVal --- and return appropriate value
return null;
}
};
Future<Object> future = executor.submit(task);
try {
p = future.get(Integer.parseInt(threadSleeptime), TimeUnit.MILLISECONDS);
} catch (Exception e) {
log.error(e + ". The function timed out after [" + threadSleeptime
+ "] miliseconds before a response was received.");
} finally {
// if task has started then don't stop it
future.cancel(false);
}
}
private static String returnString() {
return "hello";
}
public static void main(String[] args) {
timeoutFunction(returnString());
}
虽然这还不适用于Java 7及以下版本,但我相信我们应该展望未来,至少认识到Java 8等新版本中会出现的变化。
也就是说,这个新版本为Java带来了lambda和方法引用(以及新的api,这是这个问题的另一个有效解决方案)。虽然它们仍然需要一个接口,但不会创建新的对象,并且额外的类文件不会因为JVM的不同处理而污染输出目录。
这两种风格(lambda和方法引用)都需要一个具有单一方法的可用接口,该方法的签名被使用:
public interface NewVersionTest{
String returnAString(Object oIn, String str);
}
从这里开始,方法的名称不再重要。在接受lambda的地方,也接受方法引用。例如,在这里使用我们的签名:
public static void printOutput(NewVersionTest t, Object o, String s){
System.out.println(t.returnAString(o, s));
}
这只是一个简单的接口调用,直到传递lambda1:
public static void main(String[] args){
printOutput( (Object oIn, String sIn) -> {
System.out.println("Lambda reached!");
return "lambda return";
}
);
}
这将输出:
Lambda reached!
lambda return
方法引用类似。考虑到:
public class HelperClass{
public static String testOtherSig(Object o, String s){
return "real static method";
}
}
和主要:
public static void main(String[] args){
printOutput(HelperClass::testOtherSig);
}
输出将是真正的静态方法。方法引用可以是静态的、实例的、带有任意实例的非静态的,甚至是构造函数。对于构造函数,将使用类似ClassName::new的东西。
1有些人不认为这是lambda,因为它有副作用。不过,它确实以一种更直观的方式说明了如何使用。
首先用要作为参数传递的方法定义一个Interface
public interface Callable {
public void call(int param);
}
使用该方法实现一个类
class Test implements Callable {
public void call(int param) {
System.out.println( param );
}
}
//像这样调用
Callable cmd = new Test();
这允许您将cmd作为参数传递,并调用接口中定义的方法调用
public invoke( Callable callable ) {
callable.call( 5 );
}
我没有找到任何解决方案,在这里,显示如何传递方法与参数绑定到它作为一个方法的参数。下面的例子演示了如何传递一个已经绑定了参数值的方法。
步骤1:创建两个接口,一个有返回类型,另一个没有。Java也有类似的接口,但它们没有什么实际用途,因为它们不支持异常抛出。
public interface Do {
void run() throws Exception;
}
public interface Return {
R run() throws Exception;
}
我们如何使用两个接口在事务中封装方法调用的示例。注意,我们传递方法时带有实际参数。
//example - when passed method does not return any value
public void tx(final Do func) throws Exception {
connectionScope.beginTransaction();
try {
func.run();
connectionScope.commit();
} catch (Exception e) {
connectionScope.rollback();
throw e;
} finally {
connectionScope.close();
}
}
//Invoke code above by
tx(() -> api.delete(6));
另一个例子展示了如何传递一个实际返回值的方法
public R tx(final Return func) throws Exception {
R r=null;
connectionScope.beginTransaction();
try {
r=func.run();
connectionScope.commit();
} catch (Exception e) {
connectionScope.rollback();
throw e;
} finally {
connectionScope.close();
}
return r;
}
//Invoke code above by
Object x= tx(() -> api.get(id));