在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)
在这种情况下,您不能使用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或类似的东西.
因为数组和可变参数是覆盖等效的,所以以下是可能的:
@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
。在上面的例子中,由于类型变量的擦除T
是Object
,它会创建一个Object[]
数组并将其传递给需要 a 的apply
方法Double[]
。
apply
使用泛型可变参数覆盖该方法(更一般地编写任何泛型可变参数方法)将生成警告,这就是原因。(警告在 JLS 的8.4.1中是强制性的。)
因此,我实际上不建议使用它。我发布它是因为,它很有趣,它在更简单的情况下确实有效,我想解释为什么可能不应该使用它。
归档时间: |
|
查看次数: |
2250 次 |
最近记录: |