Converting an Array to List(or ArrayList) in Java – Options and their analysis

Converting an array of data into an equivalent List does seem like one of the simplest tasks which a programmer would do when coding in Java. Thinking on the same lines I set out to write a simple and short corsding tip on array to list conversion, but in the process discovered so much underlying subtext/knowledge about the 3 primary options to do so that I decided to write a full-fledged full length post on the topic. In case you need a list of quick suggestions with examples on ways to convert an array to a list(or arraylist) then you can just read the code snippets which are self-explanatory. Else, do read on to understand the interesting bit of technical information around these array to list conversion options, which has several good-to-know technical nuggets interspersed throughout.

There are many scenarios where data is present in an Array, while you need to store it in a List or, in List’s more specific subclass, an ArrayList. There are more than one commonly used ways in which an Array can be converted to a List or ArrayList. Each of these methods come with their own limitations. This tutorial analyzes the three most commonly used options along with their limitations and applicability.

Option 1: Using Arrays.asList() method to convert from an array to a List
This is one of the most common way of converting an array T[] to a List<T> using the Arrays.asList() method. It can be coded for in a single line of code as shown next –

Converting array to List using Arrays.asList()
package com.javabrahman.corejava;

import java.util.Arrays;
import java.util.List;
public class ArrayToList {

  public static void main(String args[]){
    Integer integerArray[] = {1,66,88,100, 201};
    List<Integer> integerList= Arrays.asList(integerArray);
    System.out.println(integerList);
  }

}
 OUTPUT of the above code
[1, 66, 88, 100, 201]
As you can see in the output, members of integerList have been copied from integerArray. This is what we wanted to do as well.

However, there are couple of limitations with the above instance of List<Integer>. Let us tackle these limitations one at a time. To start with, let us add the a new line to the above code which adds another number to integerList as shown below –

Adding a number to integerList after it is created
  Integer integerArray[] = {1,66,88,100, 201};
  List<Integer> integerList= Arrays.asList(integerArray);
  integerList.add(250);

Now running the above code, which tries to add an element to integerList, throws the following exception –

Exception in thread "main" java.lang.UnsupportedOperationException
  at java.util.AbstractList.add(AbstractList.java:148)
  at java.util.AbstractList.add(AbstractList.java:108)
  at com.javabrahman.corejava.ArrayToList.main(ArrayToList.java:9)

What could have gone wrong with the above code? It was converted to a List correctly. The List elements were also printed correctly. Then why is UnsupportedOperationException thrown when we try to add an element to the List?

Limitation 1 of using List instance returned by Arrays.asList() method
To find out the issue, I ran this code with debugging option on in IntelliJ IDEA to see the ‘type’ of concrete List instance created by Arrays.asList() method. Here is what I saw –

Arrays$ArrayList instance created using Arrays.asList method

As you can see in the screenshot above, the type of List instance created is mentioned as Arrays$ArrayList. integerList is not an instance of java.util.ArrayList as one would assume. Rather, it is an instance of a static nested class of Arrays class named ArrayList (denoted as Arrays$ArrayList).

The next logical question is – why does the add() operation on Arrays$ArrayList instance throw an UnsupportedOperationException?

The answer to this question is that instead of extending java.util.List, Arrays$ArrayList instead extends an abstract class named java.util.AbstractList. When add() method is invoked on an Arrays$ArrayList instance, it actually invokes AbstractList’s inherited add() method, as Arrays$ArrayList doesn’t have any overridden implementation for add() method. The default implementation of add() method in AbstractList throws an UnsupportedOperationException, and that is what we saw above.

Similarly, UnsupportedOperationException will be thrown if remove() method is called on the integerList variable of type Arrays$ArrayList. The List of type Arrays$ArrayList has been defined as a fixed size list. Elements cannot be added or removed from this List.

So, the first consideration to take when deciding to use Arrays.asList() method to convert an array to a List is to check if you will ever need to modify the contents of the resulting List. If yes, then you can skip the Arrays.asList() method which gets you an equivalent “read-only” List instance. If you don’t need to modify the List then before finalizing on Arrays.asList() you need to keep in mind its second limitation which is covered next.

Limitation 2 of using List instance returned by Arrays.asList() method
Any changes done to the original array, integerArray in our example, will reflect in the List instance, integerList, even if the changes are done in the array after the list was created. Let us see a code snippet showing the effect of this limitation –

Second limitation of using Arrays.asList()
Integer integerArray[] = {1,66,88,100, 201};
List<Integer> integerList = Arrays.asList(integerArray);
System.out.println(integerList);
integerArray[0] = 22;
System.out.println(integerList);
 OUTPUT of the above code
[1, 66, 88, 100, 201]
[22, 66, 88, 100, 201]
As you can see in the above code and output, the value of integerArray[0] was changed in the above code after the integerList was created. This change reflected in the integerList as well. This is because, the Arrays$ArrayList instance internally stores a reference to the array passed to it at the time of initialization, and uses the original array itself to store data. Hence, any change done to the original array is automatically propagated to the Arrays$ArrayList instance created out of it.

So, the second consideration to take when using Arrays.asList() method is to accept that given any change to the original array, the generated list will also change.

To summarize – Taking the 2 limitations of Arrays.asList() together, if the list created out of the array does not need to be modified post-creation, and you are fine with any changes in original array propagating into the list post-creation, then Arrays.asList() is a good option for converting an array into a List.

Let us now look at the other options available to us for converting an array to a List.

Option 2: Using ArrayList constructor with Arrays.asList() as parameter
We can use the constructor of an ArrayList which accepts a collection as an input parameter and initializes a new java.util.ArrayList instance containing the collection’s data. An ArrayList created in this manner does not have the twin disadvantages we saw in option 1 viz. being of fixed size, and being just another view into the original array rather than being an ArrayList instance on its own.

Let us now see a code snippet showing this option in use –

Creating a new ArrayList instance using constructor with collection as input
package com.javabrahman.corejava;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ArrayToList {

  public static void main(String args[]){

    Integer integerArray[] = {1,66,88,100, 201};
    List<Integer> integerList= new ArrayList<>(Arrays.asList(integerArray));
    System.out.println(integerList);
    
    //Modifying the original array
    integerArray[0]=22;
    System.out.println(integerList);
    
    //Adding a new number to integerList
    integerList.add(250);
    System.out.println(integerList);
  }

}
 OUTPUT of the above code
[1, 66, 88, 100, 201]
[1, 66, 88, 100, 201]
[1, 66, 88, 100, 201, 250]
As you can infer from the above code and its output, integerList created like this allows adding a new number(250) to the ArrayList. Also, the original array’s modification (by setting integerArray[0]=22) does not affect the newly created integerList which is now an independent instance in itself.

This method is good but not perfect. The limitation with this option is that it works only with arrays of Object/Class types and not with primitives such as int or long. This is because a List cannot be of a primitive type, and due to the same reason Arrays.asList() method also does not accept a primitive array as its input. This limitation when converting arrays of primitive types to lists, now takes us to the third way for creating a list from a given array.

Option 3: Using Java 8’s Arrays.stream() method with a Collector
Java 8’s Arrays class provides a method stream() which has overloaded versions accepting both primitive arrays and Object arrays.

Let us see a code snippet showing Java 8’s new Arrays.stream() method is use –

Converting array to List using Arrays.stream() and a Collector
package com.javabrahman.corejava;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class ArrayToList {

  public static void main(String args[]){
    //Converting a primitive 'int' array to List
    int intArray[] = {1, 11, 111, 1111, 10000};
    List<Integer> integerList = Arrays.stream(intArray).boxed().collect(Collectors.toList());
    System.out.println(integerList);
    
    //Converting an 'Integer'array to List
    Integer integerArray[] = {2, 22, 222, 2222, 20000};
    List<Integer> integerList2 = Arrays.stream(integerArray).collect(Collectors.toList());
    System.out.println(integerList2);
  }

}
 OUTPUT of the above code
[1, 11, 111, 1111, 10000]
[2, 22, 222, 2222, 20000]
In the above code, arrays of both primitive and Object types are converted to streams of their respective types first. The individual Streams are then fed, or pipelinedClick to Read tutorial explaining concept of Pipelines in Computing, to a Collector instance which accepts the Stream as input and ‘collects’ its elements into a List which is of the same type as the type of the original array.

The only difference between the code for creation of a primitive vs Object type List is the boxed() method. The boxed() method is used to convert the IntStream (a stream of primitive int type) instance returned by the stream() method for the primitive intArray, into corresponding Integer type Stream instance. boxed() is needed for int arrays because a List collector requires a stream of an Object type rather than a primitive IntStream.

Summary
In this tutorial we had an in-depth look at the 3 popularly used ways of converting a given array into an equivalent arraylist. We looked at how to code for each of these options, understood their applicability and went through their limitations

 

Digiprove sealCopyright © 2014-2019 JavaBrahman.com, all rights reserved.