144

Suppose we have a Collection<Foo>. What is the best (shortest in LoC in current context) way to transform it to Foo[]? Any well-known libraries are allowed.

UPD: (one more case in this section; leave comments if you think it's worth to create another thread for it): What about transforming Collection<Foo> to Bar[] where Bar has constructor with 1 parameter of type Foo i.e. public Bar(Foo foo){ ... } ?

Roman
  • 64,384
  • 92
  • 238
  • 332
  • 1
    [Made this answer](https://stackoverflow.com/a/51545469/1746118) with an alternate API introduced in JDK-11 to perform the same operation with similar performance and the explanation along with it. Plus the syntax matches the existing `Stream.toArray` API from the JDK. – Naman Jul 26 '18 at 18:59

10 Answers10

278

Where x is the collection:

Foo[] foos = x.toArray(new Foo[x.size()]);
Auroratic
  • 462
  • 8
  • 25
  • 41
    **simpler** (easier) but not best(memory): `x.toArray(new Foo[0])` --- **documentation**: no time to read... – user85421 Jul 20 '10 at 20:47
  • 7
    @Carlos actually, it uses better memory than `(new Foo[0])`. As per the Collection.toArray documentation, ` @param a the array into which the elements of this collection are to be stored, if it is big enough` which means it will store them directly in that new array. If you give it a size 0 array, it will make a new array, meaning you have a small array and a large array being made when such is unnecessary. – corsiKa Jul 20 '10 at 21:42
  • 5
    @glowcoder - but this can be minimized if you define a empty array once as a static constant. It's just a hint for `toArray` to create a target array of the correct type. And in this case, honestly, I wouldn't care about one extra single empty array in my application. That's far below noise level. – Andreas Dolk Jul 21 '10 at 06:28
  • 2
    @glowcoder - that's exactly why I (*tried to*) wrote that using `new Foo[0]` is simpler "but not best (memory)"... that is, I meant that my solution is easier but not best (that's the reason I used `:` ). – user85421 Jul 21 '10 at 07:26
  • 21
    Note that this code is not threadsafe, even if you're using a synchronized collection. It'll behave itself in most situations, but if an item is deleted between the call to x.size() and x.toArray(), the resulting array will contain an extra null element at the end. The `new Foo[0]` variant proposed by Carlos does not suffer this problem. – Jules Nov 19 '13 at 02:33
  • 1
    @Jules: For what it's worth it is also not suitable for some "funny" collections like `WeakHashMap`. –  May 21 '15 at 20:48
  • 1
    @Jules - where in the documentation do you see that the `new Foo[0]` version is thread safe? I'm sure that internally the implementation will still first check the size of the list, then create a new array if required, then fill it. Since the documentation does not explicitly mention thread safety, I'm pretty sure you should not rely on it being so. (edit: fix wording). – Jan de Vos Sep 12 '16 at 10:56
  • 1
    @JandeVos - Yes, it does do exactly what you say, but it does *inside a synchronized method* (if using a synchronized collection, as I described in my comment) and hence atomically without possibility of the collection being modified while that happens. This is quite obvious from the documentation for `synchronizedList` that states: "Returns a synchronized (thread-safe) list backed by the specified list." This implies that *all individual operations provided by the object are thread safe*, including the one described. doublep's suggestion, however, uses 2 operations separately, which isn't. – Jules Sep 27 '16 at 04:56
  • 1
    Surprisingly `new Foo[0]` is the most performant. It's important to realize that the JVM, or a compiler, is free to do as it pleases so long as the semantics of code are preserved. In this case it can optimize this method best when a dynamic size is *not* provided. [Source](https://shipilev.net/blog/2016/arrays-wisdom-ancients/) – geg Jan 14 '17 at 20:31
43

Alternative solution to the updated question using Java 8:

Bar[] result = foos.stream()
    .map(x -> new Bar(x))
    .toArray(size -> new Bar[size]);
Jules
  • 14,841
  • 9
  • 83
  • 130
  • 41
    This can be shortened to `Bar[] result = foos.stream().map(Bar::new).toArray(Bar[]::new);` – Lovro Pandžić Dec 27 '14 at 13:27
  • Syntax wise I'd much prefer the accepted answer. I wish people can all switch to Python. – Eric Chen Sep 12 '17 at 19:40
  • 1
    @EricChen Switch to Python - an interpreted and dynamically typed language from Java - 'compiled and statically typed language' because of coding syntax and number lines differ? Not a good idea. – RafiAlhamd Feb 21 '20 at 04:50
11

If you use it more than once or in a loop, you could define a constant

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

and do the conversion it like

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

The toArray method will take the empty array to determine the correct type of the target array and create a new array for you.


Here's my proposal for the update:

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[]{});
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
  • 1
    ups, `const` is not Java! `public static final Foo[] FOO = {}` – user85421 Jul 20 '10 at 20:55
  • 1
    why would it be public? – Zoltán Jul 25 '13 at 19:14
  • @Zoltán - why not? It's immutable, so doesn't present a safety issue. It's a little bit of clutter, but could be useful in other code, so is generally harmless. Maybe even create a central class with all of these constants, and then use `import static` to get at them. – Jules Nov 19 '13 at 02:36
  • @Jules the reference to the array is immutable, but the contents of it aren't. Anyone outside the class can replace the elements of the array freely. And on the other hand, as a rule of thumb, I believe all fields should be made private until they are needed outside the class. – Zoltán Nov 19 '13 at 08:53
  • 2
    Being zero length, there are no contents that can be changed – Jules Nov 19 '13 at 12:51
7

With JDK/11, an alternate way of converting a Collection<Foo> to an Foo[] could be to make use of Collection.toArray(IntFunction<T[]> generator) as:

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

As explained by @Stuart on the mailing list(emphasis mine), the performance of this should essentially be the same as that of the existing Collection.toArray(new T[0]) --

The upshot is that implementations that use Arrays.copyOf() are the fastest, probably because it's an intrinsic.

It can avoid zero-filling the freshly allocated array because it knows the entire array contents will be overwritten. This is true regardless of what the public API looks like.

The implementation of the API within the JDK reads:

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

The default implementation calls generator.apply(0) to get a zero-length array and then simply calls toArray(T[]). This goes through the Arrays.copyOf() fast path, so it's essentially the same speed as toArray(new T[0]).


Note:- Just that the API use shall be guided along with a backward incompatibility when used for code with null values e.g. toArray(null) since these calls would now be ambiguous because of existing toArray(T[] a) and would fail to compile.

Naman
  • 27,789
  • 26
  • 218
  • 353
6

If you use Guava in your project you can use Iterables::toArray.

Foo[] foos = Iterables.toArray(x, Foo.class);
Andrea Bergonzo
  • 3,983
  • 4
  • 19
  • 31
3

Here's the final solution for the case in update section (with the help of Google Collections):

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

But, the key approach here was mentioned in the doublep's answer (I forgot for toArray method).

Community
  • 1
  • 1
Roman
  • 64,384
  • 92
  • 238
  • 332
  • 1
    See my comment on doublep's answer about thread safety, which also applies to this solution. `new Bar[0]` avoids the issue. – Jules Nov 19 '13 at 02:44
2

For the original see doublep answer:

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

As for the update:

int i = 0;
Bar[] bars = new Bar[fooCollection.size()];
for( Foo foo : fooCollection ) { // where fooCollection is Collection<Foo>
    bars[i++] = new Bar(foo);
}    
Community
  • 1
  • 1
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
1

Actually in modern Java, the version without setting the explicit size is faster. See this SO answer:

.toArray(new MyClass[0]) or .toArray(new MyClass[myList.size()])?

This is backed up by independent research and the team at IntelliJ.

That is, this is the fastest approach today:

Foo[] foos = x.toArray(new Foo[0])

Or, even better, with a bit of safety:

Foo[] foos = x == null ? null : x.toArray(new Foo[0])
Adam Wise
  • 2,043
  • 20
  • 17
0

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

-1

For example, you have collection ArrayList with elements Student class:

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
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Jagadeesh HN
  • 59
  • 1
  • 2