varargs作为java 8中函数的输入参数

sur*_*rya 5 java java-8

在Java 8中,如何定义函数以适合varargs.

我们有这样的功能:

private String doSomethingWithArray(String... a){
   //// do something
   return "";
}
Run Code Online (Sandbox Code Playgroud)

由于某种原因,我需要使用Java 8函数调用它(因为'andThen'可以与其他函数一起使用.)

因此我想定义下面给出的东西.

Function<String... , String> doWork = a-> doSomethingWithArray(a)  ;
Run Code Online (Sandbox Code Playgroud)

这给了我编译错误.以下工作,但输入现在必须是一个数组,不能是一个单独的字符串.

Function<String[] , String> doWork = a-> doSomethingWithArray(a)  ;
Run Code Online (Sandbox Code Playgroud)

这里我提到了String,但它可以是任何Object的数组.

有没有办法使用varargs(...)而不是array([])作为输入参数?

或者,如果我创建一个类似于Function的新界面,是否可以创建类似下面的内容?

@FunctionalInterface
interface MyFunction<T... , R> {
//..
} 
Run Code Online (Sandbox Code Playgroud)

Ous*_* D. 7

在这种情况下,您不能使用varargs语法,因为它不是方法参数.

根据您使用的Function类型,您可能根本不需要它,您可以使用您的方法,而无需通过功能接口引用它们.

作为替代方案,您可以定义自己的功能界面,如下所示:

@FunctionalInterface
public interface MyFunctionalInterface<T, R> {
    R apply(T... args);
}
Run Code Online (Sandbox Code Playgroud)

然后你的声明变成:

MyFunctionalInterface<String, String> doWork = a -> doSomethingWithArray(a);
Run Code Online (Sandbox Code Playgroud)

并且doWork现在可以调用:

String one = doWork.apply("one");
String two = doWork.apply("one","two");
String three = doWork.apply("one","two","three");
...
...
Run Code Online (Sandbox Code Playgroud)

注意 - 功能接口名称只是一个占位符,可以进行改进,以与功能接口的Java命名约定保持一致,例如VarArgFunction或类似的东西.


Rad*_*def 5

因为数组和可变参数是覆盖等效的,所以以下是可能的

@FunctionalInterface
interface VarArgsFunction<T, U> extends Function<T[], U> {
    @Override
    U apply(T... args);
}

// elsewhere
VarArgsFunction<String, String> toString =
    args -> Arrays.toString(args);
String str = toString.apply("a", "b", "c");
// and we could pass it to somewhere expecting
// a Function<String[], String>
Run Code Online (Sandbox Code Playgroud)

也就是说,这有一个与一般调用方法有关的陷阱。以下抛出一个ClassCastException

static void invokeApply() {
    VarArgsFunction<Double, List<Double>> fn =
        Arrays::asList;
    List<Double> list = invokeApply(fn, 1.0, 2.0, 3.0);
}
static <T, U> U invokeApply(VarArgsFunction<T, U> fn,
                            T arg0, T arg1, T arg2) {
    return fn.apply(arg0, arg1, arg2); // throws an exception
}
Run Code Online (Sandbox Code Playgroud)

行动中的例子。

发生这种情况是因为类型擦除:调用该apply方法一般会创建一个数组,其组件类型是类型变量的擦除T。在上面的例子中,由于类型变量的擦除TObject,它会创建一个Object[]数组并将其传递给需要 a 的apply方法Double[]

apply使用泛型可变参数覆盖该方法(更一般地编写任何泛型可变参数方法)将生成警告,这就是原因。(警告在 JLS 的8.4.1中是强制性的。)

因此,我实际上不建议使用它。我发布它是因为,它很有趣,它在更简单的情况下确实有效,我想解释为什么可能不应该使用它。