将集合转换为数组的最简单方法?


125

假设我们有一个Collection<Foo>。将其转换为的最佳方法(在当前上下文中,LoC最短)是Foo[]什么?允许使用任何知名的库。

UPD:(更多的情况在本节中,发表评论,如果你认为它的价值创造另一个线程它):关于什么转变Collection<Foo>Bar[]那里Bar与1个型参数有构造函数Foo,即public Bar(Foo foo){ ... }


使用JDK-11中引入的备用API 做出了此回答,以执行具有相似性能的相同操作以及相应的说明。加上语法与Stream.toArrayJDK中现有的API 匹配。
纳曼

Answers:


256

x集合在哪里:

Foo[] foos = x.toArray(new Foo[x.size()]);

35
更简单(更容易)但不是最好(内存):x.toArray(new Foo[0]) --- 文档:没有时间阅读...
user85421

6
@Carlos实际上,它比使用更好的内存(new Foo[0])。根据Collection.toArray文档,`@param是此集合的元素要存储到的数组(如果足够大的话),这意味着它将直接将它们存储在该新数组中。如果给它一个大小为0的数组,它将创建一个新数组,这意味着您有一个较小的数组和一个较大的数组(如果不需要)。
corsiKa

4
@glowcoder-但是如果您一次定义一个空数组作为静态常量,则可以将其最小化。这只是toArray创建正确类型的目标数组的提示。老实说,在这种情况下,我不会在我的应用程序中关心一个额外的单个空数组。那远远低于噪音水平。
安德烈亚斯·多克

2
@glowcoder-这就是我(试图)写道使用new Foo[0]更简单的“但不是最好的(内存)”的原因。也就是说,我的意思是我的解决方案更简单但不是最好的(这就是我使用的原因:)。
user85421 2010年

21
请注意,即使您使用的是同步集合,此代码也不是线程安全的。它在大多数情况下都会表现出来,但是如果在调用x.size()和x.toArray()之间删除了一项,则结果数组的末尾将包含一个额外的null元素。new Foo[0]卡洛斯提出的变体不会遇到这个问题。
2013年

36

使用Java 8更新问题的替代解决方案:

Bar[] result = foos.stream()
    .map(x -> new Bar(x))
    .toArray(size -> new Bar[size]);

35
可以缩短为 Bar[] result = foos.stream().map(Bar::new).toArray(Bar[]::new);
lpandzic

在语法方面,我更喜欢可接受的答案。我希望人们都能切换到Python。
艾瑞克·陈

@EricChen切换到Python-一种来自Java的解释型和动态类型化的语言-由于编码语法和数字行的不同而导致的“编译和静态类型化的语言”?这不是一个好主意。
拉菲·阿尔罕姆德

10

如果您多次使用它或循环使用它,则可以定义一个常量

public static final Foo[] FOO = new Foo[]{};

并像这样进行转换

Foo[] foos = fooCollection.toArray(FOO);

toArray方法将使用空数组来确定目标数组的正确类型,并为您创建一个新数组。


这是我的更新建议:

Collection<Foo> foos = new ArrayList<Foo>();
Collection<Bar> temp = new ArrayList<Bar>();
for (Foo foo:foos) 
    temp.add(new Bar(foo));
Bar[] bars = temp.toArray(new Bar[]{});

1
跌宕起伏,const不是Java!public static final Foo[] FOO = {}
user85421'7

1
为什么要公开?
佐尔坦

@Zoltán-为什么不呢?它是不可变的,因此不会出现安全问题。这有点混乱,但是在其他代码中可能有用,因此通常是无害的。甚至可以使用所有这些常量创建一个中心类,然后使用import static它们来获取它们。
2013年

@Jules对数组的引用是不可变的,但它的内容不是。类之外的任何人都可以自由替换数组的元素。另一方面,根据经验,我认为在课堂外需要所有字段之前,应将所有字段设为私有。
佐尔坦

2
长度为零,没有可以更改的内容
Jules 2013年

5

与JDK / 11,转换的替代方式Collection<Foo>,以一个Foo[]可利用的Collection.toArray(IntFunction<T[]> generator)为:

Foo[] foos = fooCollection.toArray(new Foo[0]); // before JDK 11
Foo[] updatedFoos = fooCollection.toArray(Foo[]::new); // after JDK 11

正如@Stuart在邮件列表(重点是我的)所解释的那样,其性能本质上应该与现有的Collection.toArray(new T[0])-

结果是使用Arrays.copyOf()的实现是最快的,可能是因为它是一个内在的

它可以避免对新分配的数组进行零填充,因为它知道整个数组的内容都将被覆盖。无论公共API是什么样的,都是如此。

JDK中的API实现如下:

default <T> T[] toArray(IntFunction<T[]> generator) {
    return toArray(generator.apply(0));
}

默认实现调用generator.apply(0)以获得零长度数组,然后简单调用toArray(T[])。这是通过Arrays.copyOf() 快速路径进行的,因此其速度基本上与相同toArray(new T[0])


注意:-仅当将API用于带有值的代码时,才应指导API使用以及向后不兼容null例如,toArray(null)因为这些调用由于存在toArray(T[] a)而将变得模棱两可,并且无法编译。



3

对于原始内容,请参见doublep答案:

Foo[] a = x.toArray(new Foo[x.size()]);

至于更新:

int i = 0;
Bar[] bars = new Bar[fooCollection.size()];
for( Foo foo : fooCollection ) { // where fooCollection is Collection<Foo>
    bars[i++] = new Bar(foo);
}    

3

这是针对此情况的最终解决方案,位于“更新”部分(借助Google收藏夹):

Collections2.transform (fooCollection, new Function<Foo, Bar>() {
    public Bar apply (Foo foo) {
        return new Bar (foo);
    }
}).toArray (new Bar[fooCollection.size()]);

但是,在doublep的答案中提到了这里的关键方法(我忘记了toArray方法)。


1
请参阅我对doublep关于线程安全性的回答的评论,该回答也适用于此解决方案。 new Bar[0]避免了这个问题。
2013年

-1

例如,您具有元素为Student类的ArrayList集合:

List stuList = new ArrayList();
Student s1 = new Student("Raju");
Student s2 = new Student("Harish");
stuList.add(s1);
stuList.add(s2);
//now you can convert this collection stuList to Array like this
Object[] stuArr = stuList.toArray();           // <----- toArray() function will convert collection to array
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.