Java 8:带有变量参数的 Lambda

2022-09-03 01:56:42

我正在寻找一种方法来调用多个参数方法,但使用构造。在文档中,据说只有当它可以映射到功能接口时才可用。lambdalambda

我想做这样的事情:

test((arg0, arg1) -> me.call(arg0, arg1));
test((arg0, arg1, arg2) -> me.call(arg0, arg1, arg2));
...

有没有办法在不定义10个接口的情况下优雅地做到这一点,每个参数计数一个?

更新

我使用从非方法接口扩展的多个接口,并且重载了该方法。

两个参数的示例:

interface Invoker {}
interface Invoker2 extends Invoker { void invoke(Object arg0, Object arg1);}
void test(Invoker2 invoker, Object ... arguments) {
    test((Invoker)invoker, Object ... arguments);
}

void test(Invoker invoker, Object ... arguments) {
    //Use Reflection or whatever to access the provided invoker
}

我希望有可能用一个解决方案替换10个调用程序接口和10个重载方法。

我有一个合理的用例,请不要问诸如“你为什么要做这样的事情?”和“你试图解决的问题是什么?”或类似的事情。只要知道我已经想好了,这是我试图解决的合法问题。

很抱歉添加混淆,称它为调用程序,但它实际上是在我当前的用例(测试构造函数合约)中调用的。

基本上,如上所述,请考虑一种在 .lambda


答案 1

在你需要使用这样的数组。Java

test((Object[] args) -> me.call(args));

如果采用数组变量,这将起作用。如果没有,则可以使用反射来代替调用。callargs


答案 2

我目前使用的最终解决方案是定义接口的层次结构(如问题中所述),并使用默认方法来避免失败。伪代码如下所示:

interface VarArgsRunnable {
     default void run(Object ... arguments) {
          throw new UnsupportedOperationException("not possible");
     }
     default int getNumberOfArguments() {
          throw new UnsupportedOperationException("unknown");
     }
}

和四个参数的接口,例如:

@FunctionalInterface
interface VarArgsRunnable4 extends VarArgsRunnable {
     @Override
     default void run(Object ... arguments) {
          assert(arguments.length == 4);
          run(arguments[0], arguments[1], arguments[2], arguments[3]);
     }

     void run(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4);

     @Override
     default int getNumberOfArguments() {
          return 4;
     }
}

定义了从VarArgsRunnable0到VarArgsRunnable10的11个接口后,重载方法变得非常容易。

public void myMethod(VarArgsRunnable runnable, Object ... arguments) {
     runnable.run(arguments);
}

由于Java不能通过使用类似的东西来查找VarArgsRunnable的正确扩展功能接口来编写Lambda,因此需要使用正确的接口重载该方法。instance.myMethod((index, value) -> doSomething(to(index), to(value)), 10, "value")

public void myMethod(VarArgsRunnable2 runnable, Object arg0, Object arg1) {
    myMethod((VarArgsRunnable)runnable, combine(arg0, arg1));
}

private static Object [] combine(Object ... values) {
    return values;
}

由于这需要使用将 Object 转换为任何适当的类型,因此可以使用泛型进行参数化以避免这种用法。to(...)

-方法如下所示:公共静态 T to(Object value) { return (T)value; //Supress this warning }to

这个例子很蹩脚,但我用它来调用一个方法,其中多个参数是所有潜在组合的排列(用于测试目的),例如:

run((index, value) -> doTheTestSequence(index, value), values(10, 11, 12), values("A", "B", "C"));

所以这小行运行6个调用。所以你看到这是一个简洁的帮助器,能够在一行中测试多个东西,而不是定义更多或在TestNG中使用多种方法等等。

PS:不需要使用反射是一件好事,因为它不会失败,并且非常节省参数计数。


推荐