Java 8:具有可变参数的Lambda

Mar*_*ten 15 java lambda java-8

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

我想做的事情如下:

test((arg0, arg1) -> me.call(arg0, arg1));
test((arg0, arg1, arg2) -> me.call(arg0, arg1, arg2));
...
Run Code Online (Sandbox Code Playgroud)

有没有什么方法可以优雅地做到这一点而不定义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
}
Run Code Online (Sandbox Code Playgroud)

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

我有一个合理的用例,请不要问诸如"你为什么要做这样的事情?"之类的问题.并且'你想解决的问题是什么?' 或类似的东西.只要知道我已经考虑过这一点,这是我试图解决的合法问题.

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

基本上,如上所述,考虑一个在其中使用不同数量的属性的方法lambda.

Pet*_*rey 9

Java你需要使用这样的数组.

test((Object[] args) -> me.call(args));
Run Code Online (Sandbox Code Playgroud)

如果call采用数组变量,args这将起作用.如果不是,您可以使用反射代替拨打电话.


Mar*_*ten 4

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

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

以及四个参数的接口,例如:

@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;
     }
}
Run Code Online (Sandbox Code Playgroud)

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

public void myMethod(VarArgsRunnable runnable, Object ... arguments) {
     runnable.run(arguments);
}
Run Code Online (Sandbox Code Playgroud)

由于 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;
}
Run Code Online (Sandbox Code Playgroud)

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

to方法如下所示: public static T to(Object value) { return (T)value; //抑制这个警告}

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

run((index, value) -> doTheTestSequence(index, value), values(10, 11, 12), values("A", "B", "C"));
Run Code Online (Sandbox Code Playgroud)

所以这一小行运行 6 次调用。所以你会发现这是一个简洁的助手,能够在一行中测试多个内容,而不是在 TestNG 等中定义更多内容或使用多个方法......。

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

  • 这是一个实用的解决方案,但同时它也说明了 Java 只能被扭曲来完成这种事情。我想知道是否有一种优雅的方式。 (2认同)