Java 8:具有可变参数的Lambda

我正在寻找一种方法来调用多个参数方法,但使用lambda结构。 在文档中,据说lambda仅在可以映射到function接口时才可用。

我想做的事情如下:

 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使用不同数量的属性的方法。

Java您需要使用这样的数组。

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

如果call采用数组变量args这将起作用。 如果不是,您可以使用reflection代替进行调用。

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

 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无法通过使用像instance.myMethod((index, value) -> doSomething(to(index), to(value)), 10, "value")这样的东西来找到VarArgsRunnable的正确扩展function接口来组成Lambda。一个人需要使用正确的接口重载方法。

 public void myMethod(VarArgsRunnable2 runnable, Object arg0, Object arg1) { myMethod((VarArgsRunnable)runnable, combine(arg0, arg1)); } private static Object [] combine(Object ... values) { return values; } 

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

to -method看起来像这样:public static T to(Object value){return(T)value; //抑制此警告}

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

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

所以这条小线路运行了6次调用。 所以你看到这是一个很好的帮手,可以在一行中测试多个东西,而不是定义更多或者在TestNG中使用多个方法等等。

PS:不需要使用reflection是一件非常好的事情,因为它不会失败并且非常明智地保存参数。

我相信以下代码应该适合您想要的:

 public class Main { interface Invoker { void invoke(Object ... args); } public static void main(String[] strs) { Invoker printer = new Invoker() { public void invoke(Object ... args){ for (Object arg: args) { System.out.println(arg); } } }; printer.invoke("I", "am", "printing"); invokeInvoker(printer, "Also", "printing"); applyWithStillAndPrinting(printer); applyWithStillAndPrinting((Object ... args) -> System.out.println("Not done")); applyWithStillAndPrinting(printer::invoke); } public static void invokeInvoker(Invoker invoker, Object ... args) { invoker.invoke(args); } public static void applyWithStillAndPrinting(Invoker invoker) { invoker.invoke("Still", "Printing"); } } 

请注意,您不必创建lambda并将其传递给me.call,因为您已经有了对该方法的引用。 你可以像调用applyWithStillAndPrinting(printer::invoke)一样调用test(me::call) applyWithStillAndPrinting(printer::invoke)

我所做的是我自己的用例是定义一个接受varargs然后调用lambda 的辅助方法 。 我的目标是1)能够在方法中定义一个简洁和范围的函数(即lambda)和2)使得对lambda的调用非常简洁。 原始海报可能有类似的目标,因为他提到,在上面的一条评论中,希望避免为每次调用编写Object [] {…}的冗长。 也许这对其他人有用。

步骤#1:定义辅助方法:

 public static void accept(Consumer invokeMe, Object... args) { invokeMe.accept(args); } 

步骤#2:定义一个可以使用不同数量参数的lambda:

 Consumer add = args -> { int sum = 0; for (Object arg : args) sum += (int) arg; System.out.println(sum); }; 

第三步:多次调用lambda – 这简洁,这就是我想要语法糖的原因:

 accept(add, 1); accept(add, 1, 2); accept(add, 1, 2, 3); accept(add, 1, 2, 3, 4); accept(add, 1, 2, 3, 4, 5); accept(add, 1, 2, 3, 4, 5, 6);