Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In Java, data manipulation often involves converting data structures from one form to another. One common task is converting an ArrayList of Strings to a String array.

In this tutorial, we’ll explore how to accomplish this conversion seamlessly using Java’s built-in methods and techniques.

2. Introduction to the Problem

An example can help us to understand the problem quickly. Let’s say we have the following ArrayList, which contains some artists’ names:

static final List<String> INPUT_LIST = Lists.newArrayList("Michael Bolton", "Michael Jackson", "Guns and Roses", "Bryan Adams", "Air Supply");

Now, we want to convert this ArrayList to a String array, which contains the same artists’ names in the same order:

static final String[] EXPECTED_ARRAY = new String[] { "Michael Bolton", "Michael Jackson", "Guns and Roses", "Bryan Adams", "Air Supply" };

This looks like an easy task, as Java standard library provides the Collection.toArray() method to convert a collection to an array. The toArray() method returns an Object[] array. As the list is in the type List<String>, all elements are strings. So we may think it’s safe to cast the object array to String[]:

String[] result = (String[]) INPUT_LIST.toArray();

If we run this line of code, we can see this output:

java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Ljava.lang.String; 

As we can see, the ClassCastException is thrown. This is because Java’s generic types only exist at compile time. That is to say, at runtime, the array returned by the toArray() method doesn’t know its elements’ concrete types. They could be String, Integer, or even mixed by different types since the Object class is the supertype of all other types. Therefore, Java throws ClassCastException and rejects the Object[] to String[] casting.

So next, let’s see the right approaches to convert a string ArrayList to a string array. For simplicity, we’ll use unit test assertions to verify if each approach returns the expected result.

3. Filling a Predeclared String Array in a Loop

One straightforward idea to solve our problem is to walk through the string ArrayList, take every element, and fill a predeclared string array. Next, let’s implement it:

String[] result = new String[INPUT_LIST.size()];
for (int i = 0; i < INPUT_LIST.size(); i++) {
    result[i] = INPUT_LIST.get(i);
}
assertArrayEquals(EXPECTED_ARRAY, result);

In the above implementation, we first declared a string array whose length is the same as the size of the given ArrayList. Then, we fill the array in the for loop.

4. Using the toArray(T[] a) Method

We encountered ClassCastException earlier when we used the Collection.toArray() method. The Collection interface also defines another toArray() method with a parameter T[] a:

<T> T[] toArray(T[] a);

The method signature shows the method returns T[] instead of Object[]. Next, let’s look at how to use it:

String[] result = new String[INPUT_LIST.size()];
INPUT_LIST.toArray(result);
assertArrayEquals(EXPECTED_ARRAY, result);

As the code above shows, we created a new string array with enough room for the list elements. Therefore, after passing it to toArray(), the array is filled by the elements in the list.

However, if the string array we passed to toArray() doesn’t have enough space for the list elements, we’ll get a new array from toArray(): 

String[] result2 = INPUT_LIST.toArray(new String[0]);
assertArrayEquals(EXPECTED_ARRAY, result2);

5. Using the Stream API

Let’s suppose we work with Java 8 or later. We can also solve the problem using the Stream API:

String[] result = INPUT_LIST.stream()
  .toArray(String[]::new);
assertArrayEquals(EXPECTED_ARRAY, result);

Stream‘s toArray() method accepts a generator function, which allocates the returned array in the required type. In this case, we can simply take String[]‘s constructor as a method reference and pass it to toArray() as the function.

6. Java 11+

Finally, if we work with Java 11 or later, we can directly call Collection.toArray(generatorFunc) to get the converted array without converting the list to Stream first:

String[] result = INPUT_LIST.toArray(String[]::new);
assertArrayEquals(EXPECTED_ARRAY, result);

7. Conclusion

In this article, we first discussed why (String[])myList.toArray() throws ClassCastException. Then, we learned different approaches to convert a String ArrayList to a String array through examples.

As always, the complete source code for the examples is available over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.