With streams added in Java 8 we can write code like:
int[] example1 = list.stream().mapToInt(i->i).toArray();
// OR
int[] example2 = list.stream().mapToInt(Integer::intValue).toArray();
Thought process:
The simple
Stream#toArrayreturns anObject[]array, so it is not what we want. Also,Stream#toArray(IntFunction<A[]> generator)which returnsA[]doesn't do what we want, because the generic typeAcan't represent the primitive typeintSo it would be nice to have some kind of stream which would be designed to handle primitive type
intinstead of the reference type likeInteger, because itstoArraymethod will most likely also return anint[]array (returning something else likeObject[]or even boxedInteger[]would be unnatural forint). And fortunately Java 8 has such a stream which isIntStreamSo now the only thing we need to figure out is how to convert our
Stream<Integer>(which will be returned fromlist.stream()) to that shinyIntStream.Quick searching in documentation of
Streamwhile looking for methods which returnIntStreampoints us to our solution which ismapToInt(ToIntFunction<? super T> mapper)method. All we need to do is provide a mapping fromIntegertoint.Since
ToIntFunctionis functional interface we can also provide its instance via lambda or method reference.Anyway to convert Integer to int we can use
Integer#intValueso insidemapToIntwe can write:mapToInt( (Integer i) -> i.intValue() )(or some may prefer:
mapToInt(Integer::intValue).)But similar code can be generated using unboxing, since the compiler knows that the result of this lambda must be of type
int(the lambda used inmapToIntis an implementation of theToIntFunctioninterface which expects as body a method of type:int applyAsInt(T value)which is expected to return anint).So we can simply write:
mapToInt((Integer i)->i)Also, since the
Integertype in(Integer i)can be inferred by the compiler becauseList<Integer>#stream()returns aStream<Integer>, we can also skip it which leaves us withmapToInt(i -> i)
Videos
With streams added in Java 8 we can write code like:
int[] example1 = list.stream().mapToInt(i->i).toArray();
// OR
int[] example2 = list.stream().mapToInt(Integer::intValue).toArray();
Thought process:
The simple
Stream#toArrayreturns anObject[]array, so it is not what we want. Also,Stream#toArray(IntFunction<A[]> generator)which returnsA[]doesn't do what we want, because the generic typeAcan't represent the primitive typeintSo it would be nice to have some kind of stream which would be designed to handle primitive type
intinstead of the reference type likeInteger, because itstoArraymethod will most likely also return anint[]array (returning something else likeObject[]or even boxedInteger[]would be unnatural forint). And fortunately Java 8 has such a stream which isIntStreamSo now the only thing we need to figure out is how to convert our
Stream<Integer>(which will be returned fromlist.stream()) to that shinyIntStream.Quick searching in documentation of
Streamwhile looking for methods which returnIntStreampoints us to our solution which ismapToInt(ToIntFunction<? super T> mapper)method. All we need to do is provide a mapping fromIntegertoint.Since
ToIntFunctionis functional interface we can also provide its instance via lambda or method reference.Anyway to convert Integer to int we can use
Integer#intValueso insidemapToIntwe can write:mapToInt( (Integer i) -> i.intValue() )(or some may prefer:
mapToInt(Integer::intValue).)But similar code can be generated using unboxing, since the compiler knows that the result of this lambda must be of type
int(the lambda used inmapToIntis an implementation of theToIntFunctioninterface which expects as body a method of type:int applyAsInt(T value)which is expected to return anint).So we can simply write:
mapToInt((Integer i)->i)Also, since the
Integertype in(Integer i)can be inferred by the compiler becauseList<Integer>#stream()returns aStream<Integer>, we can also skip it which leaves us withmapToInt(i -> i)
Unfortunately, I don't believe there really is a better way of doing this due to the nature of Java's handling of primitive types, boxing, arrays and generics. In particular:
List<T>.toArraywon't work because there's no conversion fromIntegertoint- You can't use
intas a type argument for generics, so it would have to be anint-specific method (or one which used reflection to do nasty trickery).
I believe there are libraries which have autogenerated versions of this kind of method for all the primitive types (i.e. there's a template which is copied for each type). It's ugly, but that's the way it is I'm afraid :(
Even though the Arrays class came out before generics arrived in Java, it would still have to include all the horrible overloads if it were introduced today (assuming you want to use primitive arrays).
Either:
Foo[] array = list.toArray(new Foo[0]);
or:
Foo[] array = new Foo[list.size()];
list.toArray(array); // fill the array
Note that this works only for arrays of reference types. For arrays of primitive types, use the traditional way:
List<Integer> list = ...;
int[] array = new int[list.size()];
for(int i = 0; i < list.size(); i++) array[i] = list.get(i);
Update:
It is recommended now to use list.toArray(new Foo[0]);, not list.toArray(new Foo[list.size()]);.
From JetBrains Intellij Idea inspection:
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).
An alternative in Java 8:
String[] strings = list.stream().toArray(String[]::new);
Since Java 11:
String[] strings = list.toArray(String[]::new);
From the javadocs:
Like the toArray() method, this method acts as bridge between array-based and collection-based APIs. Further, this method allows precise control over the runtime type of the output array, and may, under certain circumstances, be used to save allocation costs.
This means that the programmer is in control over what type of array it should be.
For example, for your ArrayList<Integer> instead of an Integer[] array you might want a Number[] or Object[] array.
Furthermore, the method also checks the array that is passed in. If you pass in an array that has enough space for all elements, the the toArray method re-uses that array. This means:
Integer[] myArray = new Integer[myList.size()];
myList.toArray(myArray);
or
Integer[] myArray = myList.toArray(new Integer[myList.size()]);
has the same effect as
Integer[] myArray = myList.toArray(new Integer[0]);
Note, in older versions of Java the latter operation used reflection to check the array type and then dynamically construct an array of the right type. By passing in a correctly sized array in the first place, reflection did not have to be used to allocate a new array inside the toArray method. That is no longer the case, and both versions can be used interchangeably.
It is declared generically so that you can write code such as
Integer[] intArray = list.toArray(new Integer[0]);
without casting the array coming back.
It is declared with the following annotation:
@SuppressWarnings("unchecked")
In other words, Java is trusting you to pass in an array parameter of the same type, so your error does not occur.
Eg ArrayList<Integer> should return Interger[] instead of Object[]
Is it being of java's generics