The difference in these two approaches for converting a collection to an array object

which is the fundamental difference in these two following approaches for transforming a collection into an array object

ArrayList<String> iName = new ArrayList<String>(); String[] array= iName.toArray(new String[iName.size()]);//1 String[] array= iName.toArray(new String[0]);//2 

when should approach-1 be used and when is approach-2?

+5
source share
4 answers

The difference between these two approaches:

  String[] array = iName.toArray(new String[iName.size()]); String[] array = iName.toArray(new String[0]); 

very different if there is a chance that the original set ( iName in this case) can be changed at the same time. If concurrency is not possible, then the first line is preferred.

This is not strictly applied in your example, where is the original ArrayList collection, which is not thread safe. But if the original collection is a parallel collection, then the behavior of the parallel modification is significant. In this case, the first line has a race condition. The calling thread first gets the size; another thread can then add or remove an element by resizing it. But then the calling thread selects the array with the old size and passes it to toArray .

This does not result in an error. Cases are clearly defined if you carefully read the specification of Collection.toArray(T[]) . If the collection grew, a new array would be allocated for it, which would make the caller's array redundant. If the collection is reduced, the tail of the array will end with zero elements. This is not necessarily an error, but any code that consumes the resulting array must be prepared to handle zeros, which can be unpleasant.

Passing a zero-length array avoids these problems at the possible cost of allocating a useless zero-length array. (You can store the cached version, but it adds clutter.) If the collection is empty, a zero-length array is simply returned. However, if the collection has elements, the collection itself selects an array of the correct size and fills it. This avoids the race condition of the caller in an array of "wrong" size.

In the Java 8 Streams API, the Stream.toArray method avoids this problem by passing a call to the factory array. This allows the caller to specify the type, but allows the collection to specify the desired size. This has not yet been finalized until Collections . This applies to RFE JDK-8060192 .

+2
source

The first approach is better because you create one array, and toArray uses it to store input list items. The second approach leads toArray create another array, since it cannot store anything in an empty array.

You will encounter other behavior if you pass an array to the method whose length is greater than the size of the input list, since in this case the size element of the array (where size is the size of the input list) will be set to zero.

The only time it makes sense to switch to a method, an array smaller than the size of the list is if you do not create an instance of the array when you call the method, but use an existing array:

 array = iName.toArray(array); 

Here you do not know in advance if the array will be large enough to contain iName elements. If not, toArray will return a new array. If so, toArray will return the input array.

+4
source

In principle, both approaches do the same and will produce the same outputs, but under the hood they behave a little differently.

In the first approach, since the size of the array is large enough, List can copy its elements to the array and returns the same one. When you use the second approach, the List class does almost exactly for your first approach: create a new array with the correct size to copy the values.

From the point of view of efficiency: in the first approach, one array is created and not used, which is not very good even when creating the array, it does not require much time or processing power, but it is redundant and should not be done. If you know the size of the list, all collections know their size, you should use the first approach.

0
source

If you look at the implementation, you can understand the difference:

 public <T> T[] toArray(T[] a) { if (a.length < size) // Make a new array of a runtime type, but my contents: return (T[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } 

If the array is smaller than ArrayList, a new array is created. If the provided array is larger than the ArrayList, it will be used to copy the contents of the list support array.

In terms of performance, it is best practice to use the first approach ( iName.toArray(new String[iName.size()]) ), but the penalty for the second approach is small (an array of size 0 is created).

I personally use the second approach, as I think it makes the code more readable.

0
source

All Articles