我想知道是否有一种简单的,优雅的和可重用的方式来传递字符串和字符串数组到期望变量的方法。
/**
* The entry point with a clearly separated list of parameters.
*/
public void separated(String p1, String ... p2) {
merged(p1, p2, "another string", new String[]{"and", "those", "one"});
}
/**
* For instance, this method outputs all the parameters.
*/
public void merged(String ... p) {
// magic trick
}
即使所有类型都是一致的(String
),我也找不到一种方法来告诉JVM flatten p2并将其注入合并的参数列表?
此时唯一的方法是创建一个新数组,将所有内容复制到其中并传递给函数。
任何想法?
编辑
根据你的建议,以下是我将使用的通用方法:
/**
* Merge the T and T[] parameters into a new array.
*
* @param type the destination array type
* @param parameters the parameters to merge
* @param <T> Any type
* @return the new holder
*/
@SuppressWarnings("unchecked")
public static <T> T[] normalize(Class<T> type, Object... parameters) {
List<T> flatten = new ArrayList<>();
for (Object p : parameters) {
if (p == null) {
// hum... assume it is a single element
flatten.add(null);
continue;
}
if (type.isInstance(p)) {
flatten.add((T) p);
continue;
}
if (p.getClass().isArray() &&
p.getClass().getComponentType().equals(type)) {
Collections.addAll(flatten, (T[]) p);
} else {
throw new RuntimeException("should be " + type.getName() +
" or " + type.getName() +
"[] but was " + p.getClass());
}
}
return flatten.toArray((T[]) Array.newInstance(type, flatten.size()));
}
normalize(String.class, "1", "2", new String[]{"3", "4", null}, null, "7", "8");
我认为没有办法将标量和数组隐式地扁平化为单个数组。
我能想到的最干净的解决方案是使用辅助函数:
// generic helper function
public static<T> T[] join(T scalar, T[] arr) {
T[] ret = Arrays.copyOfRange(arr, 0, arr.length + 1);
System.arraycopy(ret, 0, ret, 1, arr.length);
ret[0] = scalar;
return ret;
}
public void separated(String p1, String ... p2) {
merged(join(p1, p2));
}
修改merge
的签名为:
public<T> void merged(T ... p)
将至少允许您调用合并没有问题。但是,您必须处理字符串数组作为参数。
在separated
中,参数p2
为String[]
。merged
方法可以接受单个String[]
参数或字符串序列,但不是两者的混合物,所以我认为除了构建一个新数组(这就是varargs在幕后所做的)之外,您没有太多选择。
From varargs doc
最后一个参数类型后面的三个句号表示最终参数可以作为数组或序列传递参数。
它清楚地说明了an array OR a sequence of arguments
,因此您必须自己平坦数组,例如NPE建议的。
我认为创建一个新的数组是可行的。
例如,您可以使用Apache Commons中的ArrayUtils
来实现这一点。
ArrayUtils.addAll(p2, p1);
最诚挚的问候,托马斯。
我怀疑你能做到这一点,Java编译器应该将合并(p1, p2)转换为合并(p1, p2 [0], p2[1]…p [p];长度]),但我不认为他们曾经想要创建这样一个智能编译器(如果合并(p1, p2)也存在,它也会产生问题)。
你可以这样做(使用伪语法):
import com.google.common.collect.Lists
import java.util.Arrays
separated ( String p1, String... p2 ) {
merged ( Lists.asList ( p1, p2 ) )
}
merged ( List<String> p ) {
...
}
merged ( String ... p ) {
merged ( Arrays.asList ( p )
}
Arrays来自标准JDK, Lists来自Guava。两个asList()方法都在下划线数组上创建视图,而不是副本,因此没有太多的速度/内存问题。
我认为没有更简单的方法了。是的,复制到一个新的数组,正如其他人建议的那样,更简单,但时间/内存消耗。如果您的数组很小,创建和访问list可能会比复制慢,但是对于较大的数组,复制将会增加开销。
我喜欢Sebastian的建议:您定义了merge()的包装器,该包装器在飞行中使数组变平。只要merge()不是第三方方法,并且您可以更改它,就可以很好地工作。否则,我在这里做类似的事情