【问题标题】:Create a Parameter that is a Varying Function创建一个可变函数的参数
【发布时间】:2017-08-16 21:08:19
【问题描述】:

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

【问题讨论】:

  • 制作自定义界面。
  • 方法签名过载?你有一组特定的输入参数吗?
  • 更新问题

标签: java scala java-8 metaprogramming covariance


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    怎么样,

    一个执行器接口:

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

    【讨论】:

      【解决方案3】:

      根据您的定义,doSomethingFancy("hello", this::doFancyThing);(我假设您想要这个而不是第二个示例中的doSomething("hello", this::doFancyThing);)应该调用doFancyThing("hello"),这是不可能的:它缺少两个参数! doSomethingFancy("hello", this::doFancyThing2); 也是如此,它调用 doFancyThing2("hello")

      如果你想一想,你会发现改变doSomethingFancy的定义并没有帮助:它无能为力(除了返回nullobject、@987654329等琐碎的事情@, ETC。)。所以当语言甚至不允许你声明它时,这是一件好事。

      两种实际可能性:

      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. 使用可变参数提供所有参数:

        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 -&gt; doFancyThing((Object) args(0), (String) args(1), (List) args(2)) 部分提取到一个泛型方法中,因此调用看起来像

        doSomething(toVarArgs(this::doFancyThing), "hello", "a", Collections.<Integer> emptyList()));
        

      这留作练习。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-02-02
        • 2018-07-19
        • 2011-10-30
        • 2011-08-08
        • 1970-01-01
        • 1970-01-01
        • 2013-09-27
        • 1970-01-01
        相关资源
        最近更新 更多