757

How can I convert a List<Integer> to int[] in Java?

I'm confused because List.toArray() actually returns an Object[], which can be cast to neither Integer[] nor int[].

Right now I'm using a loop to do so:

int[] toIntArray(List<Integer> list) {
  int[] ret = new int[list.size()];
  for(int i = 0; i < ret.length; i++)
    ret[i] = list.get(i);
  return ret;
}

Is there's a better way to do this?

This is similar to the question How can I convert int[] to Integer[] in Java?.

starball
  • 20,030
  • 7
  • 43
  • 238
  • 11
    You can only cast to Integer[] by using: `Integer[] arr = (Integer[])list.toArray(new Integer[list.size]);` – Hardcoded Jul 05 '10 at 15:48
  • @ripper234, eddie's solution is worse than the one on the question. actually the original one is technically the best as long as the List is RandomAccess impl (even it will be properly unrolled and the bounds check for array removed) – bestsss Dec 16 '11 at 09:31
  • 1
    @Hardcoded you might want to edit your comment to use list.size() method and drop the unnecessary cast. – sactiw Apr 09 '13 at 16:10
  • @sactiw How should I do this? This comment is written 3 years ago and you can only edit your comments for the first 5 minutes. – Hardcoded Apr 29 '13 at 12:22
  • 2
    Is there a better way to do this now in Java 8? – Makoto Jun 16 '14 at 00:14
  • 2
    (@Makoto : see [Pshemo's answer](http://stackoverflow.com/a/23945015/3789665)) – greybeard Feb 09 '16 at 19:11
  • 6
    int[] arr = listOfIntegers.stream().mapToInt(x->x).toArray(); – old_soul_on_the_run Sep 22 '18 at 23:49

16 Answers16

1037

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#toArray returns an Object[] array, so it is not what we want. Also, Stream#toArray(IntFunction<A[]> generator) which returns A[] doesn't do what we want, because the generic type A can't represent the primitive type int

  • So it would be nice to have some kind of stream which would be designed to handle primitive type int instead of the reference type like Integer, because its toArray method will most likely also return an int[] array (returning something else like Object[] or even boxed Integer[] would be unnatural for int). And fortunately Java 8 has such a stream which is IntStream

  • So now the only thing we need to figure out is how to convert our Stream<Integer> (which will be returned from list.stream()) to that shiny IntStream.

    Quick searching in documentation of Stream while looking for methods which return IntStream points us to our solution which is mapToInt(ToIntFunction<? super T> mapper) method. All we need to do is provide a mapping from Integer to int.

    Since ToIntFunction is functional interface we can also provide its instance via lambda or method reference.

    Anyway to convert Integer to int we can use Integer#intValue so inside mapToInt we 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 in mapToInt is an implementation of the ToIntFunction interface which expects as body a method of type: int applyAsInt(T value) which is expected to return an int).

    So we can simply write:

    mapToInt((Integer i)->i)
    

    Also, since the Integer type in (Integer i) can be inferred by the compiler because List<Integer>#stream() returns a Stream<Integer>, we can also skip it which leaves us with

    mapToInt(i -> i)
    
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • 7
    Clearly the best solution. Too bad it lacks explanation. – Pimp Trizkit Nov 26 '15 at 14:53
  • 22
    @PimpTrizkit Updated this answer a little. Hope it is clearer now. – Pshemo Nov 26 '15 at 15:32
  • 3
    @Pshemo - Thanks! I didn't personally need an explanation. But I hate seeing the perfect answer without one! Regardless, your explanation did educate me and was helpful. I wonder why the `mapTo...` functions don't allow for `null` lambda.... like sort does.... which makes it default to a default behavior... in this case, `i -> i` would be a perfect default behavior. – Pimp Trizkit Nov 27 '15 at 03:29
  • I guess this answer is faster than ColinD's answer using Guava, right? – vefthym Mar 02 '17 at 10:47
  • 2
    @vefthym I didn't test it, but I suspect that both solution work on same simple principle so I would expect similar speed (but feel free to benchmark it). One advantage of this answer is that it doesn't require additional libraries as long as we have Java 8. – Pshemo Mar 02 '17 at 15:55
  • thanks to this, I learned about streams of primitive types. Great solution and explanation, thank you. – S3lvatico Jan 04 '20 at 09:54
  • Hands down the best solution! – Adi Sivasankaran Apr 28 '20 at 05:47
  • Unfortunately, this doesn't seem to work with `byte`, `short`, `char`, or `float` arrays... – Solomon Ucko Aug 18 '20 at 18:58
  • @SolomonUcko True, there are no `Stream`s corresponding to those primitive types, so also there are no methods in Stream class like `mapToByte(...)`. – Pshemo Aug 18 '20 at 19:15
  • This should be the accepted answer in my opinion. Also, could you please update the answer to use method reference (if you feel so)? – Dhruv Singhal Dec 03 '20 at 04:40
  • Here's the equivalent for a byte array, borrowing from [this answer](https://stackoverflow.com/questions/32459683#answer-32470838) (and its comments): `byte[] array = list.stream().filter(Objects::nonNull).mapToInt(i -> i).collect(ByteArrayOutputStream::new, (b, i) -> b.write((byte) i), (b1, b2) -> { try { b2.writeTo(b1); } catch(IOException e) { } }).toByteArray();` – Steve Chambers Oct 12 '21 at 07:41
  • This exactly why people prefer Python to Java. – Yuqiu G. May 14 '23 at 11:48
259

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>.toArray won't work because there's no conversion from Integer to int
  • You can't use int as a type argument for generics, so it would have to be an int-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).

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 33
    Also see ColinD's answer about guava's Ints.toArray(Collection) – ron Jun 16 '11 at 12:34
  • 9
    @JonSkeet you mean like the horrible overloads that exists already in the Arrays class for `binarySearch`, `copyOf`, `copyOfRange`...? I wonder why they couldn't add another set of horrible overloads. – Simon Forsberg May 24 '13 at 20:30
  • 1
    @ron ColinD's answer doesn't give anything but what the OP already had - for loop to fill primitive array with non-primitive one. – Tomáš Zato Mar 06 '15 at 19:47
  • meanwhile at Oracle java engineers are fixated with overcomplicating the language with modules... – Gubatron Feb 17 '16 at 20:41
  • 2
    @bvdb: I'm saying that without other libraries (which basically still have the loop, but in their code not yours), I don't believe there's a better approach. That's a significantly stronger assertion than saying I don't know whether or not there is a better approach. – Jon Skeet Jun 20 '16 at 13:50
  • ...and you can't avoid primitives until Java language designers improve it - https://stackoverflow.com/questions/14477743/why-are-there-primitive-datatype-in-java – MasterJoe Sep 25 '18 at 01:00
221

In addition to Commons Lang, you can do this with Guava's method Ints.toArray(Collection<Integer> collection):

List<Integer> list = ...
int[] ints = Ints.toArray(list);

This saves you having to do the intermediate array conversion that the Commons Lang equivalent requires yourself.

dimo414
  • 47,227
  • 18
  • 148
  • 244
ColinD
  • 108,630
  • 30
  • 201
  • 202
  • 4
    Unfortunately, the intermediate array is hidden inside Guava: `Object[] boxedArray = collection.toArray();` – kamczak Feb 25 '14 at 12:05
  • 9
    "Fortunately, the intermediate array is hidden inside Guava." - Fixed that for you. ;) – Eddified Aug 05 '16 at 21:03
182

The easiest way to do this is to make use of Apache Commons Lang. It has a handy ArrayUtils class that can do what you want. Use the toPrimitive method with the overload for an array of Integers.

List<Integer> myList;
 ... assign and fill the list
int[] intArray = ArrayUtils.toPrimitive(myList.toArray(new Integer[myList.size()]));

This way you don't reinvent the wheel. Commons Lang has a great many useful things that Java left out. Above, I chose to create an Integer list of the right size. You can also use a 0-length static Integer array and let Java allocate an array of the right size:

static final Integer[] NO_INTS = new Integer[0];
   ....
int[] intArray2 = ArrayUtils.toPrimitive(myList.toArray(NO_INTS));
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
Eddie
  • 53,828
  • 22
  • 125
  • 145
  • The `toPrimitive` link is broken. – Mark Byers Nov 29 '12 at 09:35
  • Here's a link to 2.6 Commons Lang API: [toPrimitive](http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/ArrayUtils.html#toPrimitive(java.lang.Integer[])) – StackEng2010 Mar 13 '13 at 16:10
  • 12
    Note that this will entail 2 allocations and copies: `myList.toArray()` will create an `Integer[]` and populate it, while `ArrayUtils.toPrimitive()` will allocate an `int[]` and unbox the input. – atanamir May 24 '13 at 02:56
84

Java 8 has given us an easy way to do this via streams...

Using the collections stream() function and then mapping to ints, you'll get an IntStream. With the IntStream we can call toArray() which gives us int []

int [] ints = list.stream().mapToInt(Integer::intValue).toArray();

to int []

to IntStream

Devon_C_Miller
  • 16,248
  • 3
  • 45
  • 71
Pumphouse
  • 2,013
  • 17
  • 26
62

Use:

int[] toIntArray(List<Integer> list)  {
    int[] ret = new int[list.size()];
    int i = 0;
    for (Integer e : list)
        ret[i++] = e;
    return ret;
}

This slight change to your code is to avoid expensive list indexing (since a List is not necessarily an ArrayList, but it could be a linked list, for which random access is expensive).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • I dont understand: looking up an elepment in an array is not slow. It runs in O, where n is the size of the array, ie it's not dependent on the size of the array at all or anything. In C: myarray[c] is the same as: myarray + c * sizeof( myarray[0] ) ... which runs *very* fast. – Hugh Perkins Jul 04 '10 at 01:26
  • 5
    The method takes List as argument, not all implementations have fast random access (like ArrayList) – Arjan Jul 04 '10 at 22:03
  • 1
    @Hugh: The difference is not how the array is accessed, but how the List is accessed. `list.get(i)` performs bounds checks and stuff for each access. I don't know whether the new solution is actually better, but Mike says so at least, so perhaps it is. Edit: I forgot that Java allows indexing into a linked list (I'm used to C++'s std::list, which does not allow it). So what arjantop said about non-ArrayList is true as well; indexing isn't necessarily fast even without the bounds checks. – Lajnold Jul 04 '10 at 22:06
  • @Lajnold The bounds checks for an `ArrayList` are free in a modern JIT. However, I'd prefer if Java more followed STL and implemented only methods which really make sense (`LinkedList::get(int)` does not as it may be arbitrary slow). – maaartinus Apr 25 '15 at 17:57
  • @maaartinus The entire purpose of interfaces is to separate implementation from interface. It makes perfect sense the way it is solved in Java if you understand the underlying idea. [Here](https://www2.ccs.neu.edu/research/demeter/papers/context-journal/node16.html) is some information about it. – Nearoo Apr 13 '18 at 17:15
  • @Nearoo No, it's a BS. The fact that you want to separate implementation from interface doesn't give you the freedom to spoil the interface, e.g., by lack of timing guarantees for most important operations. Luckily, hardly anybody uses `LinkedList`, so assuming `List::get(int)` to be a constant time operation is rather safe. – maaartinus Apr 13 '18 at 20:10
  • The `List`-interface is a so called "abstract data type". It's created without an implementation in mind. There are many different datatypes for different purposes, and many implementations with different performances. ArrayList adds a new element in O(n), and has lookup O(1). Linked list has it vice versa. Why would you restrict interfaces to only one? If you only want to support a specific runtime, you could just write "ArrayList" as a parameter type. Otherwise, the runtime can be noted in a comment. It is up to the coient to use or not use a method, it's not the responsibility of the class. – Nearoo Apr 13 '18 at 22:17
  • @maaartinus If a method or class doesn't guarantee a certain property in the documentation, the client musn't expect that property. You can't just go around using methods and expect them to be implemented in a "fast" way.It's not a programmers responsibility to create fast methods for you. His responsibility is to keep to his promises. In case of lists, no promises concerning efficiency is given. That's the core of the idea of interaces by the way. – Nearoo Apr 13 '18 at 22:50
  • Is there a reason behind only allowing Lists instead of Iterables? Or is it just to fit the question? Thanks. – lue Jun 04 '20 at 15:52
14

Here is a Java 8 single line code for this:

public int[] toIntArray(List<Integer> intList){
    return intList.stream().mapToInt(Integer::intValue).toArray();
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Noor Nawaz
  • 2,175
  • 27
  • 36
12

If you are simply mapping an Integer to an int then you should consider using parallelism, since your mapping logic does not rely on any variables outside its scope.

int[] arr = list.parallelStream().mapToInt(Integer::intValue).toArray();

Just be aware of this

Note that parallelism is not automatically faster than performing operations serially, although it can be if you have enough data and processor cores. While aggregate operations enable you to more easily implement parallelism, it is still your responsibility to determine if your application is suitable for parallelism.


There are two ways to map Integers to their primitive form:

  1. Via a ToIntFunction.

    mapToInt(Integer::intValue)
    
  2. Via explicit unboxing with lambda expression.

    mapToInt(i -> i.intValue())
    
  3. Via implicit (auto-) unboxing with lambda expression.

    mapToInt(i -> i)
    

Given a list with a null value

List<Integer> list = Arrays.asList(1, 2, null, 4, 5);

Here are three options to handle null:

  1. Filter out the null values before mapping.

    int[] arr = list.parallelStream().filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();
    
  2. Map the null values to a default value.

    int[] arr = list.parallelStream().map(i -> i == null ? -1 : i).mapToInt(Integer::intValue).toArray();
    
  3. Handle null inside the lambda expression.

    int[] arr = list.parallelStream().mapToInt(i -> i == null ? -1 : i.intValue()).toArray();
    
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
  • 1
    Note that `mapToInt(Integer::intValue)` and `mapToInt(i -> i.intValue())` are strictly identical (two ways of expressing the exact same method call), and all three are effectively identical (same bytecode). – AndrewF Feb 13 '18 at 00:38
  • This is awesome, thanks for sharing it.! – kzs Jun 02 '21 at 14:59
9

This simple loop is always correct! no bugs

  int[] integers = new int[myList.size()];
  for (int i = 0; i < integers.length; i++) {
      integers[i] = myList.get(i);
  }
THANN Phearum
  • 1,969
  • 22
  • 19
  • 3
    "Valid" is not the same as "ideal", and performance problems can be considered bugs. `List#get(int)` is not guaranteed to be a constant-time operation, as you may have assumed, so it shouldn't be used for iteration. Instead, use an iterator, which is designed for this use case. Either use the Java 5+ foreach loop or call `List#iterator()` and work with the iterator. Also, the list's size could change during this loop, leading to either an `IndexOutOfBoundsException` or an incomplete array. Many iterator implementations have well-documented strategies to handle this situation. – AndrewF Feb 13 '18 at 00:30
  • 1
    Far better than the dog's dinner that is Java streams – garryp Nov 17 '21 at 23:56
  • This is ***identical*** to the one in the question. The question was *"Is there's a better way to do this?"*. How does this answer the question? Most of the other answers attempt to answer the question. – Peter Mortensen Apr 13 '22 at 19:37
8

I've noticed several uses of for loops, but you don't even need anything inside the loop. I mention this only because the original question was trying to find less verbose code.

int[] toArray(List<Integer> list) {
    int[] ret = new int[ list.size() ];
    int i = 0;
    for( Iterator<Integer> it = list.iterator();
         it.hasNext();
         ret[i++] = it.next() );
    return ret;
}

If Java allowed multiple declarations in a for loop the way C++ does, we could go a step further and do for(int i = 0, Iterator it...

In the end though (this part is just my opinion), if you are going to have a helping function or method to do something for you, just set it up and forget about it. It can be a one-liner or ten; if you'll never look at it again you won't know the difference.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Loduwijk
  • 1,950
  • 1
  • 16
  • 28
5

There is really no way of "one-lining" what you are trying to do, because toArray returns an Object[] and you cannot cast from Object[] to int[] or Integer[] to int[].

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
neesh
  • 5,167
  • 6
  • 29
  • 32
  • 5
    You *can* cast between Object[] and Integer[] due to array covariance - but you can't cast between int[] and Integer[]. – Jon Skeet Jun 06 '09 at 20:35
  • thanks for correcting me I will edit my answer to reflect what you said. – neesh Jun 06 '09 at 20:38
4
int[] ret = new int[list.size()];       
Iterator<Integer> iter = list.iterator();
for (int i=0; iter.hasNext(); i++) {       
    ret[i] = iter.next();                
}                                        
return ret;                              
robd
  • 9,646
  • 5
  • 40
  • 59
gerardw
  • 5,822
  • 46
  • 39
3

Also try Dollar (check this revision):

import static com.humaorie.dollar.Dollar.*
...

List<Integer> source = ...;
int[] ints = $(source).convert().toIntArray();
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dfa
  • 114,442
  • 31
  • 189
  • 228
2

With Eclipse Collections, you can do the following if you have a list of type java.util.List<Integer>:

List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = LazyIterate.adapt(integers).collectInt(i -> i).toArray();

Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);

If you already have an Eclipse Collections type like MutableList, you can do the following:

MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = integers.asLazy().collectInt(i -> i).toArray();

Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);

Note: I am a committer for Eclipse Collections

Donald Raab
  • 6,458
  • 2
  • 36
  • 44
2

I would recommend you to use the List<?> skeletal implementation from the Java collections API. It appears to be quite helpful in this particular case:

package mypackage;

import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Test {

    // Helper method to convert int arrays into Lists
    static List<Integer> intArrayAsList(final int[] a) {
        if(a == null)
            throw new NullPointerException();
        return new AbstractList<Integer>() {

            @Override
            public Integer get(int i) {
                return a[i]; // Autoboxing
            }
            @Override
            public Integer set(int i, Integer val) {
                final int old = a[i];
                a[i] = val; // Auto-unboxing
                return old; // Autoboxing
            }
            @Override
            public int size() {
                return a.length;
            }
        };
    }

    public static void main(final String[] args) {
        int[] a = {1, 2, 3, 4, 5};
        Collections.reverse(intArrayAsList(a));
        System.out.println(Arrays.toString(a));
    }
}

Beware of boxing/unboxing drawbacks.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

Using a lambda you could do this (compiles in JDK lambda):

public static void main(String ars[]) {
    TransformService transformService = (inputs) -> {
        int[] ints = new int[inputs.size()];
        int i = 0;
        for (Integer element : inputs) {
            ints[ i++ ] = element;
        }
        return ints;
    };

    List<Integer> inputs = new ArrayList<Integer>(5) { {add(10); add(10);} };

    int[] results = transformService.transform(inputs);
}

public interface TransformService {
    int[] transform(List<Integer> inputs);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
NimChimpsky
  • 46,453
  • 60
  • 198
  • 311
  • 2
    You could not have done that when the question was asked, but this is a good way to handle the situation now (assuming you have upgraded Java). What you have done could be further modified to provide a general way to transform lots of things with the same methodology. +1 – Loduwijk Jul 23 '13 at 15:43
  • 7
    The solution here is only in the loop code. The rest (functional interface, lambda, main method, list with dummy data) is extraneous and doesn't help answer the question. – AndrewF Feb 13 '18 at 00:45