让一个Java函数接受集合或数组

14

我正在尝试编写一个函数,它接收一些字符串并对它们进行处理。

我想做的唯一一件事情就是遍历这些字符串。目前,我得到了一种令人尴尬的构造方式,大致是:

public void foo(String[] myStrings){
    foo(java.util.Arrays.asList(myStrings));
}

public void foo(Iterable<String> myStrings){
    for(String i : myStrings){
        bar(i);
    }
}

这感觉有些冗余,因为

for(String i : myStrings){
    bar(i);
}

对于类型为String[]的myStrings而言,上述代码是完全有效的。

有没有一个类可以让foo接受集合和数组两种类型?

3个回答

13

请参见为什么数组不能赋值给Iterable?

简短回答:不能。据我所知,数组类型是合成代码,因此并未实现Iterable或任何其他类型。您需要提供重载方法或要求客户在调用处调用Arrays.asList


4
谢谢,我想我仍在试图说服Java,在它内心深处,它是Python。 - BostonJohn
2
哈哈,这里没有鸭子类型 - 抱歉。 :) - Thorn G
3
欢迎来到冗长编程的世界。Java基于WET原则,而不是DRY原则(即写两遍一切,而不是不要重复自己)。 - akuhn

3
尽管数组可以在for-each循环中使用,但它们并未实现Iterable接口。有两种可能性,一是像您所述那样重载方法,或者只提供可迭代的变体并强制客户端调用Arrays.asList()。
如果您想提供数组重载,可以将其签名从简单数组更改为varargs:
public void foo(String... myStrings){
    foo(java.util.Arrays.asList(myStrings));
}

在这种情况下,要注意原始数组和原始包装器数组之间的不兼容性:
static void foo(int... ints) {}
foo(new Integer[] {1, 2}); // compile error

并且:

static void foo(Integer... integers) {}
foo(new int[] { 1, 2 }); // compile error

还有最晦涩的,带有通用可变参数:

static <T> T[] foo(T... ts) {
    return ts;
}

如果您传递一个整数数组:
Integer[] integers = { 1, 2 };
System.out.println(Arrays.deepToString(foo(integers)));
> [1, 2]
< p > ts 的值是一个包含 2 个整数元素的数组:12

然而,如果传递一个原始 int 数组,则会发生有趣的事情:

int[] ints = { 1, 2 };
System.out.println(Arrays.deepToString(foo(ints)));
> [[1, 2]]

在这种情况下,ts的值是一个整数数组的数组(int [] []),只有一个元素,即最初传递的数组。原因是int不是Object(自动装箱在这里无法帮助),而整数数组是Object,因此T类型参数的值变为int []

3

不幸的是,数组没有实现Iterable,尽管 for-each 循环在两者上都可以工作。

您可以专门只接受Iterable,因为传递数组有点老式(数组相对于ArrayList的性能优势微不足道)。现有的数组可以轻松包装并转换为List,使用 Arrays.asList(T... a)


这是一个不错的选择。我在编写任何新代码时都使用ArrayLists,但是有很多数组是我继承下来的。 - BostonJohn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接