创建一个可变函数的参数



在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的定义是无济于事的:它无能为力(除了像返回nullobjectfunction.hashCode()等琐碎的事情(。因此,当语言甚至不允许你声明它时,这是一件好事。

两种实际可能性:

  1. 提供缺少的参数作为函数的一部分:

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

    这行得通,效果很好。

  2. 使用 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()));
    

这留作练习。

相关内容

  • 没有找到相关文章

最新更新