Dushmantha
Dushmantha

Reputation: 3051

List to varargs with pre-defined size or without size

What is the better way to convert List to varargs to call below 'builder( String... s )' method.

builder( stringList.toArray( new String[stringList.size()] ) );//with pre-defined array size

or

builder( stringList.toArray( new String[0] ) );//without predefined size

For example

void test() {

  List<String> stringList = new ArrayList<>();
  builder( stringList.toArray( new String[stringList.size()] ) );//call builder method with pre-difining array size
  builder( stringList.toArray( new String[0] ) );//call builder method with array size 0
}

void builder( String... s )
{
}

I faced this question in a review and I was suggested that builder(stringList.toArray(new String[0])) is more efficient than using builder(stringList.toArray(new String[stringList.size()])).

Is there a significant difference between these two?

Thanks

Upvotes: 3

Views: 622

Answers (4)

Joop Eggen
Joop Eggen

Reputation: 109577

To my understanding

stringList.toArray( new String[stringList.size()] ) )

is more efficient. The reason:

The argument is needed to have an actual type (String) for a generic List<String>, where the generic type parameter is erased at run-time.

The argument is used for the resulting array if its size matches the list size.

If the size is 0, the passed array is discarded.

So passing a correct array saves one object creation.

Of course list.size() is called extra. So it might be slower. I doubt it.


Correction

See Arrays of Wisdom of the Ancients. A correct benchmark shows the inverse: new String[0] being faster. I just overflew the very interesting analysis, and it seems:

  • (an extra short lived new String[0] is irrelevant;)
  • doing the array copying local in the toArray method allows a different, faster array copy;
  • (and then there is the extra call to size.)

Mind, I did not sufficiently thorough read the article; it really is interesting.

Conclusion (counter-intuitively): new T[0] is faster.

Mind that:

  • code checkers might still think differently and issue a warning;
  • this is with warming up: till the hotspot JIT kicks in, it may be the other way around.

Upvotes: 5

Eugene
Eugene

Reputation: 120938

There is a difference and it's mainly outlined by the Alexey Shipilev. Long story short:

toArray(new T[0]) seems faster, safer, and contractually cleaner, and therefore should be the default choice now

Upvotes: 2

Oleg Cherednik
Oleg Cherednik

Reputation: 18245

I thought that c.toArray(new String[c.size()])) is more efficient, because we define here an array with required size.

BUT!!

IntelliJ IDEA has Collection.toArray() inspection, which is on by default. This is description:

There are two styles to convert a collection to an array: either using a pre-sized array (like c.toArray(new String[c.size()])) or using an empty array (like c.toArray(new String[0]).

In older Java versions using pre-sized array was recommended, as the reflection call which is necessary to create an array of proper size was quite slow. However since late updates of OpenJDK 6 this call was intrinsified, making the performance of the empty array version the same and sometimes even better, compared to the pre-sized version. Also passing pre-sized array is dangerous for a concurrent or synchronized collection as a data race is possible between the size and toArray call which may result in extra nulls at the end of the array, if the collection was concurrently shrunk during the operation.

This inspection allows to follow the uniform style: either using an empty array (which is recommended in modern Java) or using a pre-sized array (which might be faster in older Java versions or non-HotSpot based JVMs).

So it seems, that after JDK6, we should use c.toArray(new String[0]). My personal opinion, is that it doesn't matter what aporoach to use this time. Only if profiler says that this is a bottle neck, then we should worry about it.

Upvotes: 1

Eran
Eran

Reputation: 393886

builder(stringList.toArray(new String[0])) is slightly less efficient since you create an empty array that will be discarded and never used after the method returns. toArray will have to create a new array in order to store the elements of the List.

On the other hand, builder(stringList.toArray(new String[stringList.size()])) passes an array of the required length to the toArray method, and therefore that method will use that array instead of creating a new array.

Upvotes: 2

Related Questions