在Java和Scala中,我将如何执行以下操作:
我希望能够将函数作为函数参数有些变化的参数传递到函数中。例如,这就是我现在在 Java 中被锁定的内容:
public void doSomething(Object object, Action1<Object> function) {
function.call(object);
}
public void doOtherThing(Object obj) {
System.out.println(obj);
}
doSomething("hello", this::doOtherThing);
这就是我希望能够做的:
public void doSomethingFancy(Object object, <Some Function Type Here> function) {
function.call(object);
}
public void doFancyThing(Object obj1, String str1, List list1) {
// do stuff
}
public void doFancyThing2(Object obj1, RandomObj rObj, Integer int1) {
// do stuff
}
...
doSomething("hello", this::doFancyThing);
doSomething("hello", this::doFancyThing2);
基本上,我希望输入函数具有可变类型的输入参数。ActionN 不起作用,因为这会将对象数组传递到我的doFancyThing
方法中,并且显然无法编译。
任何只有一个抽象方法的接口都是函数接口,因此可以使用 lambda 函数或方法引用来实现。
@FunctionalInterface
public class MyFancyInterface {
void call(Object obj1, String str1, List list1);
}
怎么样,
执行器接口:
public interface Executor<T> {
void execute(T source);
}
一个简单的执行器:
public class SimpleExecutor implements Executor<String> {
@Override
public void execute(String source) {
System.out.println(source);
}
}
花哨的遗嘱执行人:
public class FancyExecutor implements Executor<Object>{
@Override
public void execute(Object source) {
System.out.println("doing some fancy stuff");
}
}
一个动作:
public class Action {
public <T> void doSomething(T source, Executor<T> executor) {
executor.execute(source);
}
}
最后:
public static void main(String [] args) {
Action action = new Action();
action.doSomething("hey there", new SimpleExecutor());
action.doSomething(new Object(), new FancyExecutor());
}
根据你的定义,doSomethingFancy("hello", this::doFancyThing);
(我假设你想要这个而不是第二个示例中的doSomething("hello", this::doFancyThing);
(应该调用doFancyThing("hello")
,这是不可能的:它缺少两个参数!同样,对于doSomethingFancy("hello", this::doFancyThing2);
,它调用doFancyThing2("hello")
。
如果你稍微考虑一下,你应该会发现改变doSomethingFancy
的定义是无济于事的:它无能为力(除了像返回null
、object
、function.hashCode()
等琐碎的事情(。因此,当语言甚至不允许你声明它时,这是一件好事。
两种实际可能性:
-
提供缺少的参数作为函数的一部分:
public <T> void doSomething(T object, Action1<T> function) { function.call(object); } doSomething("hello", x -> doFancyThing(x, "a", Collections.<Integer> emptyList())); doSomething("hello", x -> doFancyThing2(x, some other arguments));
这行得通,效果很好。
-
使用 varargs 提供所有参数:
public void doSomething(Action1<Object[]> function, Object... args) { function.call(object); } doSomething(args -> doFancyThing((Object) args(0), (String) args(1), (List) args(2)), "hello", "a", Collections.<Integer> emptyList()));
您可以将
args -> doFancyThing((Object) args(0), (String) args(1), (List) args(2))
部分提取到泛型方法,因此调用如下所示doSomething(toVarArgs(this::doFancyThing), "hello", "a", Collections.<Integer> emptyList()));
这留作练习。