创建一个变量函数的参数

时间:2017-08-16 21:08:20

标签: java scala java-8 metaprogramming covariance

在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方法,而且显然无法编译。

3 个答案:

答案 0 :(得分:0)

任何只有一个抽象方法的接口都是一个功能接口,因此可以使用lambda函数或方法引用来实现。

@FunctionalInterface
public class MyFancyInterface {
    void call(Object obj1, String str1, List list1);
}

答案 1 :(得分:0)

怎么样,

执行者界面:

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

答案 2 :(得分:0)

根据您的定义doSomethingFancy("hello", this::doFancyThing);(我假设您希望在第二个示例中使用此代替doSomething("hello", this::doFancyThing);)应该调用doFancyThing("hello"),这是不可能的:它缺少两个参数!同样适用于调用doSomethingFancy("hello", this::doFancyThing2);的{​​{1}}。

如果你仔细想一想,你应该发现更改doFancyThing2("hello")的定义无济于事:它无能为力(除了返回doSomethingFancy,{{null之外的琐事1}},object等)。因此,当语言不能让你宣布它时,这是一件好事。

两种实际可能性:

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

    function.hashCode()

    这很有效,效果很好。

  2. 使用varargs提供所有参数:

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

    您可以将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))
  3. 这是一项练习。