149

This may be a bit of an easy, headdesk sort of question, but my first attempt surprisingly completely failed to work. I wanted to take an array of primitive longs and turn it into a list, which I attempted to do like this:

long[] input = someAPI.getSomeLongs();
List<Long> inputAsList = Arrays.asList(input); //Total failure to even compile!

What's the right way to do this?

Eran Medan
  • 44,555
  • 61
  • 184
  • 276
Brandon Yarbrough
  • 37,021
  • 23
  • 116
  • 145

17 Answers17

134

Since Java 8 you can now use streams for that:

long[] arr = { 1, 2, 3, 4 };
List<Long> list = Arrays.stream(arr).boxed().collect(Collectors.toList());
Lii
  • 11,553
  • 8
  • 64
  • 88
marcinj
  • 48,511
  • 9
  • 79
  • 100
118

I found it convenient to do using apache commons lang ArrayUtils (JavaDoc, Maven dependency)

import org.apache.commons.lang3.ArrayUtils;
...
long[] input = someAPI.getSomeLongs();
Long[] inputBoxed = ArrayUtils.toObject(input);
List<Long> inputAsList = Arrays.asList(inputBoxed);

it also has the reverse API

long[] backToPrimitive = ArrayUtils.toPrimitive(objectArray);

EDIT: updated to provide a complete conversion to a list as suggested by comments and other fixes.

Eran Medan
  • 44,555
  • 61
  • 184
  • 276
  • 4
    Considering that this creates an _array_ of Longs, _not a List_, it doesn't answer OP's question and gets my downvote. How the heck did this get 56 upvotes and the coveted "check"??? – user949300 Aug 13 '14 at 17:53
  • 7
    Because people can easily do `Arrays.asList(ArrayUtils.toObject(input))` probably. – Eran Medan Aug 13 '14 at 21:22
  • 1
    I agree with @user949300. This doesn't answer the question. – dev4life Jun 19 '15 at 19:50
  • 1
    This answer should be updated to provide a complete conversion to a list. However, it is an efficient step towards the solution. – Jim Jeffers Jul 29 '15 at 16:11
  • 2
    @JimJeffers - thanks, updated to included the complete conversion. Since the OP included `List = Arrays.asList(inputBoxed)` in their question I found it redundant to repeat it as I thought it was obvious, I guess I was wrong... – Eran Medan Aug 13 '15 at 22:56
  • @PatrickRoberts - well, I'll be... good catch. The reason is that I copied it 1:1 from the question without even looking, but that's no excuse :) (in any case I fixed the question as well so it won't distract) thanks! (God knows how many times I saw the question and didn't notice it...) – Eran Medan Aug 31 '15 at 06:02
  • I tried it and it points to error in the second line. Java doesn't recognize ArrayUtils. Is it because we have to use streams from now? – Talgat May 27 '18 at 05:47
  • @Talgat - you will need to add it as a dependency :) I updated the answer with some info on how (maven dep, import statement) – Eran Medan May 31 '18 at 21:51
  • That's why complexities are asked in interview questions. You are iterating through the list two times. I'd rather prefer to iterate through the arr and make it a list to avoid two iterations. – Ravi Soni Sep 05 '19 at 20:49
  • @RaviSoni yeah, I see your point, but 1) it has the same big O, iterating on the same list twice is still O(n) and 2) 99% use cases this would be a major premature optimization in my opinion. – Eran Medan Sep 06 '19 at 00:09
36
import java.util.Arrays;
import org.apache.commons.lang.ArrayUtils;

List<Long> longs = Arrays.asList(ArrayUtils.toObject(new long[] {1,2,3,4}));
Marco Pelegrini
  • 492
  • 4
  • 6
35

hallidave and jpalecek have the right idea—iterating over an array—but they don't take advantage of a feature provided by ArrayList: since the size of the list is known in this case, you should specify it when you create the ArrayList.

List<Long> list = new ArrayList<Long>(input.length);
for (long n : input)
  list.add(n);

This way, no unnecessary arrays are created only to be discarded by the ArrayList because they turn out to be too short, and no empty "slots" are wasted because ArrayList overestimated its space requirements. Of course, if you continue to add elements to the list, a new backing array will be needed.

Community
  • 1
  • 1
erickson
  • 265,237
  • 58
  • 395
  • 493
  • 1
    I tend to leave out the length specification unless the code is proven to be part of a performance hot spot or the array is expected to be extremely large. I think that leaving out the length makes the code slightly more readable. – hallidave Apr 18 '09 at 16:28
20

A bit more verbose, but this works:

    List<Long> list = new ArrayList<Long>();
    for (long value : input) {
        list.add(value);
    }

In your example it appears that Arrays.asList() is interpreting the input as list of long[] arrays instead of a list of Longs. A bit surprising, for sure. Autoboxing just doesn't work the way you want it to in this case.

hallidave
  • 9,579
  • 6
  • 31
  • 27
18

As another possibility, the Guava library provides this as Longs.asList(), with similar utility classes for the other primitive types.

import com.google.common.primitives.Longs;

long[] input = someAPI.getSomeLongs();
List<Long> output = Longs.asList(input);
Pang
  • 9,564
  • 146
  • 81
  • 122
Trevor Robinson
  • 15,694
  • 5
  • 73
  • 72
8

The question asked about how to turn an array into a list. Most answers so far showed how to create a new list with the same contents as the array, or referred to third-party libraries. However, there are simple, built-in options for this sort of conversion. Some of them have already been sketched in other answers (e.g. this one). But I'd like to point out and elaborate certain degrees of freedom for the implementation here, and show the potential benefits, drawbacks and caveats.

There are at least two important distinctions to be made:

  • Whether the resulting list should be a view on the array or whether it should be a new list
  • Whether the resulting list should be modifiable or not

The options will be summarized here quickly, and a complete example program is shown at the bottom of this answer.


Creating a new list versus creating a view on the array

When the result should be a new list, then one of the approaches from the other answers may be used:

List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());

But one should consider the drawbacks of doing this: An array with 1000000 long values will occupy roughly 8 Megabytes of memory. The new list will also occupy roughly 8 Megabytes. And of course, the full array has to be traversed while creating this list. In many cases, creating a new list is simply not necessary. Instead, it is sufficient to create a view on the array:

// This occupies ca. 8 MB
long array[] = { /* 1 million elements */ }

// Properly implemented, this list will only occupy a few bytes,
// and the array does NOT have to be traversed, meaning that this
// operation has nearly ZERO memory- and processing overhead:
List<Long> list = asList(array);

(See the example at the bottom for an implementation of the toList method)

The implication of having a view on the array are that changes in the array will be visible in the list:

long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);

System.out.println(list.get(1)); // This will print 34

// Modify the array contents:
array[1] = 12345;

System.out.println(list.get(1)); // This will now print 12345!

Fortunately, creating a copy (that is, a new list that is not affected by modifications in the array) from the view is trivial:

List<Long> copy = new ArrayList<Long>(asList(array));

Now, this is a true copy, equivalent to what is achieved with the stream-based solution that was shown above.


Creating a modifiable view or an unmodifiable view

In many cases, it will be sufficient when the list is read-only. The contents of the resulting list will often not be modified, but only passed to downstream processing that only reads the list.

Allowing for modifications of the list raises some questions:

long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);

list.set(2, 34567);           // Should this be possible?
System.out.println(array[2]); // Should this print 34567?
list.set(3, null);            // What should happen here?
list.add(99999);              // Should this be possible?

It is possible to create a list view on the array that is modifiable. This means that changes in the list, like setting a new value at a certain index, will be visible in the array.

But it is not possible to create a list view that is structurally modifiable. This means that it is not possible to do operations that affect the size of the list. This is simply because the size of the underlying array cannot be changed.


The following is a MCVE showing the different implementation options, and the possible ways of using the resulting lists:

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.RandomAccess;

public class PrimitiveArraysAsLists
{
    public static void main(String[] args)
    {
        long array[] = { 12, 34, 56, 78 };

        // Create VIEWS on the given array
        List<Long> list = asList(array);
        List<Long> unmodifiableList = asUnmodifiableList(array);

        // If a NEW list is desired (and not a VIEW on the array), this
        // can be created as well:
        List<Long> copy = new ArrayList<Long>(asList(array));

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        

        // Modify a value in the array. The changes will be visible
        // in the list and the unmodifiable list, but not in
        // the copy.
        System.out.println("Changing value at index 1 of the array...");
        array[1] = 34567;

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        

        // Modify a value of the list. The changes will be visible
        // in the array and the unmodifiable list, but not in
        // the copy.
        System.out.println("Changing value at index 2 of the list...");
        list.set(2, 56789L);

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        


        // Certain operations are not supported:
        try
        {
            // Throws an UnsupportedOperationException: This list is 
            // unmodifiable, because the "set" method is not implemented
            unmodifiableList.set(2, 23456L);
        }
        catch (UnsupportedOperationException e) 
        {
            System.out.println("Expected: " + e);
        }

        try
        {
            // Throws an UnsupportedOperationException: The size of the
            // backing array cannot be changed
            list.add(90L);
        }
        catch (UnsupportedOperationException e) 
        {
            System.out.println("Expected: " + e);
        }


        try
        {
            // Throws a NullPointerException: The value 'null' cannot be  
            // converted to a primitive 'long' value for the underlying array
            list.set(2, null);
        }
        catch (NullPointerException e)
        {
            System.out.println("Expected: " + e);
        }

    }

    /**
     * Returns an unmodifiable view on the given array, as a list.
     * Changes in the given array will be visible in the returned
     * list.
     *  
     * @param array The array
     * @return The list view
     */
    private static List<Long> asUnmodifiableList(long array[])
    {
        Objects.requireNonNull(array);
        class ResultList extends AbstractList<Long> implements RandomAccess
        {
            @Override
            public Long get(int index)
            {
                return array[index];
            }

            @Override
            public int size()
            {
                return array.length;
            }
        };
        return new ResultList();
    }

    /**
     * Returns a view on the given array, as a list. Changes in the given 
     * array will be visible in the returned list, and vice versa. The
     * list does not allow for <i>structural modifications</i>, meaning
     * that it is not possible to change the size of the list.
     *  
     * @param array The array
     * @return The list view
     */
    private static List<Long> asList(long array[])
    {
        Objects.requireNonNull(array);
        class ResultList extends AbstractList<Long> implements RandomAccess
        {
            @Override
            public Long get(int index)
            {
                return array[index];
            }

            @Override
            public Long set(int index, Long element)
            {
                long old = array[index];
                array[index] = element;
                return old;
            }

            @Override
            public int size()
            {
                return array.length;
            }
        };
        return new ResultList();
    }

}

The output of the example is shown here:

array           : [12, 34, 56, 78]
list            : [12, 34, 56, 78]
unmodifiableList: [12, 34, 56, 78]
copy            : [12, 34, 56, 78]
Changing value at index 1 of the array...
array           : [12, 34567, 56, 78]
list            : [12, 34567, 56, 78]
unmodifiableList: [12, 34567, 56, 78]
copy            : [12, 34, 56, 78]
Changing value at index 2 of the list...
array           : [12, 34567, 56789, 78]
list            : [12, 34567, 56789, 78]
unmodifiableList: [12, 34567, 56789, 78]
copy            : [12, 34, 56, 78]
Expected: java.lang.UnsupportedOperationException
Expected: java.lang.UnsupportedOperationException
Expected: java.lang.NullPointerException
Marco13
  • 53,703
  • 9
  • 80
  • 159
7

Another way with Java 8.

long[] input = someAPI.getSomeLongs();
LongStream.of(input).boxed().collect(Collectors.toList()));
ravenskater
  • 702
  • 1
  • 7
  • 20
7

No, there is no automatic conversion from array of primitive type to array of their boxed reference types. You can only do

long[] input = someAPI.getSomeLongs();
List<Long> lst = new ArrayList<Long>();

for(long l : input) lst.add(l);
jpalecek
  • 47,058
  • 7
  • 102
  • 144
6

I'm writing a small library for these problems:

long[] input = someAPI.getSomeLongs();
List<Long> = $(input).toList();

In the case you care check it here.

Matthew Read
  • 1,365
  • 1
  • 30
  • 50
dfa
  • 114,442
  • 31
  • 189
  • 228
5

Another way with Java 8.

final long[] a = new long[]{1L, 2L};
final List<Long> l = Arrays.stream(a).boxed().collect(Collectors.toList());
Community
  • 1
  • 1
Jin Kwon
  • 20,295
  • 14
  • 115
  • 184
  • 1
    When returning the list (not assigning it), I found I had to do: `Arrays.stream(a).boxed().collect(Collectors.toList());` – Jon Oct 28 '15 at 19:06
  • 3
    This is identical to [this existing answer](https://stackoverflow.com/a/23117638). – Pang Oct 19 '17 at 08:25
3

Combining Pavel and Tom's answers we get this

   @SuppressWarnings("unchecked")
    public static <T> List<T> asList(final Object array) {
        if (!array.getClass().isArray())
            throw new IllegalArgumentException("Not an array");
        return new AbstractList<T>() {
            @Override
            public T get(int index) {
                return (T) Array.get(array, index);
            }

            @Override
            public int size() {
                return Array.getLength(array);
            }
        };
    }
Duncan McGregor
  • 17,665
  • 12
  • 64
  • 118
2

I know this question is old enough, but... you can also write your own conversion method:

@SuppressWarnings("unchecked")
public static <T> List<T> toList(Object... items) {

    List<T> list = new ArrayList<T>();

    if (items.length == 1 && items[0].getClass().isArray()) {
        int length = Array.getLength(items[0]);
        for (int i = 0; i < length; i++) {
            Object element = Array.get(items[0], i);
            T item = (T)element;
            list.add(item);
        }
    } else {
        for (Object i : items) {
            T item = (T)i;
            list.add(item);
        }
    }

    return list;
}

After you include it using static import, possible usages could be:

    long[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    List<Long> list = toList(array);

or

    List<Long> list = toList(1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l);
Pavel Netesa
  • 2,092
  • 1
  • 16
  • 11
  • 2
    regarding: `catch (ArrayIndexOutOfBoundsException ex) { /* Finished getting array elements */ }`, you are a terrible person. – Brandon Yarbrough Oct 15 '12 at 23:44
  • Hey, man, thanks for that! Your ironical remark made me find a better solution - getting the array's length through Array.getLength(). – Pavel Netesa Oct 16 '12 at 16:44
  • 1
    Fantastic! I'm glad my sardonic attitude led to progress instead of just general bad feelings all around :) Really, it's not a good idea to use exceptions except in very unusual conditions. They're surprisingly expensive to create. This new version is much, MUCH faster. – Brandon Yarbrough Oct 17 '12 at 22:42
2

You can use transmorph :

Transmorph transmorph = new Transmorph(new DefaultConverters());
List<Long> = transmorph.convert(new long[] {1,2,3,4}, new TypeReference<List<Long>>() {});

It also works if source is an array of ints for example.

cchabanois
  • 141
  • 1
  • 3
2

If you want similar semantics to Arrays.asList then you'll need to write (or use someone else's) customer implementation of List (probably through AbstractList. It should have much the same implementation as Arrays.asList, only box and unbox values.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
1

While it is possible to create a new List and add all the values to it (via for loop or streams), I have been working on really big arrays and get poor performance. Therefore I created my own easy to use primitive array wrapper class.

Example:

long[] arr = new long[] {1,2,3};
PrimativeList<Long> list = PrimativeList.create(arr); // detects long[] and returns PrimativeList<Long>

System.out.println(list.get(1)); // prints: 2
list.set(2, 15);
System.out.println(arr[2]);  // prints: 15

Get it here: https://github.com/Sf298/Sauds-Toolbox/blob/master/src/main/java/PrimitiveArrayWrapper/PrimitiveList.java

NOTE: I haven't fully tested it yet, so let me know if you find any bugs/issues.

sf298
  • 33
  • 1
  • 6
0

You can use LongStream for that

List<Long> longs = LongStream.of(new long[]{1L, 2L, 3L}).boxed()
                             .collect(Collectors.toList());