Convert List to Array in Java and an Array Back to a List

Convert list to array in Java with the three toArray() methods, get an int[] from a list of Integer, and turn arrays back into lists with asList().

Methods that convert a List to an array and an array to a List, marked as copy or view

A List becomes an array in Java through list.toArray(String[]::new) or list.toArray(new String[0]), and an array becomes a List again through Arrays.asList(array), List.of(array) or new ArrayList<>(Arrays.asList(array)), depending on whether the list must change later. Every way to convert a list to an array creates a copy, and so does every way back except Arrays.asList(), which wraps the original array.

We need these conversions at the border between two APIs, for example when our service collects values in a List and a library method expects a String[], or when a method returns an array and we want to sort, filter or extend it as a list.

The following example converts a list of names to an array and back into a list that can grow.

List<String> names = List.of("ana", "li", "raj");
String[] array = names.toArray(String[]::new);               // [ana, li, raj]
List<String> back = new ArrayList<>(Arrays.asList(array));   // [ana, li, raj]
boolean added = back.add("tom");                             // true

Notice that the array has the type String[], not Object[], because we pass the array constructor. Next we cover the three toArray() methods, primitive conversions with int[], the four kinds of lists we can get from an array, and the pitfalls of each one.

1. List to Array with toArray()

The Collection interface, and so every List, has three toArray() methods. They all return a new array with the elements in list order, and they differ in the type of the array they return.

Methods that convert a List to an array and an array to a List, marked as copy or view
Every conversion creates a copy, except Arrays.asList(), which is a fixed-size view of the original array
MethodReturnsSince
toArray()Object[]Java 1.2
toArray(T[] a)T[], reuses a if the list fitsJava 1.2
toArray(IntFunction<T[]> generator)T[] created by the generatorJava 11

The method without arguments returns an Object[], and casting it to String[] fails at runtime. Because of type erasure, the list does not know at runtime that it holds strings, so we pass the array type ourselves with toArray(String[]::new) or toArray(new String[0]).

List<String> cities = new ArrayList<>(List.of("Pune", "Oslo"));
Object[] objects = cities.toArray();                       // [Pune, Oslo]
String[] typed = cities.toArray(String[]::new);            // [Pune, Oslo]
String[] typed2 = cities.toArray(new String[0]);           // [Pune, Oslo]
String[] broken = (String[]) cities.toArray();             // ClassCastException

1.1. Empty or Presized Array Argument

The method toArray(T[] a) checks the length of the array we pass. If the list fits, the method copies the elements into our array and returns that same array. If the list does not fit, it creates a new array of the same type with the exact size of the list.

When our array is longer than the list, only the slot right after the last element is set to null. The slots behind it keep their old values, which can confuse code that reads the array to its end.

List<String> trio = List.of("ana", "li", "raj");
String[] big = {"x", "x", "x", "x", "x"};
String[] filled = trio.toArray(big);           // [ana, li, raj, null, x]
boolean sameArray = filled == big;             // true
String[] fresh = trio.toArray(new String[0]);  // [ana, li, raj]

We pass an empty array or a generator, never a presized array. On current HotSpot JVMs the empty-array form is as fast as the presized form or faster, and it cannot leave stale values behind. It is also safe for a list that another thread changes between size() and toArray().

2. List of Integer to int[]

No toArray() method returns a primitive array, because type arguments are always objects. A stream bridges the gap, since mapToInt() unboxes each Integer into an IntStream, and IntStream.toArray() returns an int[].

List<Integer> seats = List.of(12, 7, 30);
int[] seatArray = seats.stream().mapToInt(Integer::intValue).toArray();   // [12, 7, 30]
List<Long> ids = List.of(5L, 9L);
long[] idArray = ids.stream().mapToLong(Long::longValue).toArray();      // [5, 9]

A null element throws a NullPointerException during unboxing. If the list can contain null, we filter it out first or map it to a default value such as 0.

List<Integer> withGap = Arrays.asList(4, null, 8);
int[] crash = withGap.stream().mapToInt(Integer::intValue).toArray();   // NullPointerException
int[] clean = withGap.stream().filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();   // [4, 8]

3. Array to List with Copy or View Semantics

Turning an array into a list has four common forms, and they behave differently on add(), on set() and on null elements. Picking the wrong one leads to an UnsupportedOperationException in production or to changes that show up in an unexpected place.

Codeadd() / remove()set()Changes the arraynull elements
Arrays.asList(arr)UnsupportedOperationExceptionAllowedYes, it is a viewAllowed
List.of(arr)UnsupportedOperationExceptionUnsupportedOperationExceptionNo, copyNullPointerException
Arrays.stream(arr).toList()UnsupportedOperationExceptionUnsupportedOperationExceptionNo, copyAllowed
new ArrayList<>(Arrays.asList(arr))AllowedAllowedNo, copyAllowed

The method Arrays.asList() returns a fixed-size list that uses the array as its storage. Writing through the list changes the array and the other way round, but nothing can change the size. The comparison with a real new ArrayList matters whenever the list leaves our method.

String[] colors = {"red", "green"};
List<String> view = Arrays.asList(colors);
String old = view.set(0, "blue");          // "red"
String first = colors[0];                  // "blue", the array changed
view.add("pink");                          // UnsupportedOperationException

The method List.of() copies the array into an unmodifiable list and rejects null. The ArrayList copy is the only form that we can freely change.

String[] tags = {"java", null};
List<String> rejected = List.of(tags);              // NullPointerException
List<String> growable = new ArrayList<>(Arrays.asList(tags));
boolean ok = growable.add("arrays");                // true
String text = growable.toString();                  // "[java, null, arrays]"

To add the elements of an array to a list that already exists, Collections.addAll(list, array) does it without creating an intermediate list.

4. The Arrays.asList() Trap with int[]

The method Arrays.asList() takes varargs of an object type, so an int[] becomes a single element, and the result is a List<int[]> with size 1. The compiler accepts this without a warning, which makes it a classic bug.

int[] scores = {70, 85, 90};
List<int[]> wrong = Arrays.asList(scores);
int wrongSize = wrong.size();                                  // 1
List<Integer> right = Arrays.stream(scores).boxed().toList();  // [70, 85, 90]
List<Integer> mutable = IntStream.of(scores).boxed().collect(Collectors.toCollection(ArrayList::new));   // [70, 85, 90]

The stream method toList() was added in Java 16 and returns an unmodifiable list. More options, including Guava and Apache Commons Lang, are in the article on how to convert a primitive array to a List.

5. Filtering While Converting

When only some elements belong in the array, a stream filters and converts in one pass. The result keeps the order of the list even with parallelStream(), because a List is an ordered source and toArray() respects the encounter order.

List<String> files = List.of("a.txt", "b.png", "c.txt", "d.txt");
String[] texts = files.stream().filter(f -> f.endsWith(".txt")).toArray(String[]::new);           // [a.txt, c.txt, d.txt]
String[] inParallel = files.parallelStream().filter(f -> f.endsWith(".txt")).toArray(String[]::new);   // [a.txt, c.txt, d.txt]

Streams also convert the elements on the way, for example with map(String::toUpperCase) before toArray(). The conversion between a stream and an array has its own guide with the primitive stream types.

6. Passing a List to a Varargs Method

Varargs parameters are arrays, so a list must be converted before the call. Say a backup tool collects the folder names of a path in a List, because the number of levels depends on the user and the date. The method Path.of(String first, String… more) takes the first segment and an array for the rest.

List<String> parts = new ArrayList<>(List.of("backups", "2026", "10"));
parts.add("db.sql");
Path target = Path.of(parts.getFirst(), parts.subList(1, parts.size()).toArray(String[]::new));
String pathText = target.toString();   // "backups/2026/10/db.sql" on Linux and macOS

The method getFirst() comes from the SequencedCollection interface added in Java 21, and subList() returns a view, so only the final toArray() call copies the remaining segments.

7. List and Array Conversion FAQs

Readers who convert between lists and arrays every day keep running into the same four questions.

7.1. Why does list.toArray() without an argument give an Object[]?

Generic types are erased at runtime, so an ArrayList<String> holds an Object[] inside and cannot create a String[] on its own. The overloads with an array or a generator give it the runtime type to create.

7.2. Is new String[0] slower than new String[list.size()]?

No. On HotSpot, the zero-length version is as fast or faster, because the JVM can allocate and fill the new array in one step without clearing it first. The presized version only helps if we reuse an existing array on purpose.

7.3. Does Arrays.asList() copy the array?

No. It returns a list backed by the original array, so changes through set() or through the array show up in both. For a separate copy, we use List.of(array) or new ArrayList<>(Arrays.asList(array)).

7.4. How do we convert a List of arrays to a 2D array?

We pass the generator of the two-dimensional array type to toArray(). The rows are copied as references, so the inner arrays are shared between the list and the new array.

List<int[]> rows = List.of(new int[]{1, 2}, new int[]{3, 4});
int[][] grid = rows.toArray(int[][]::new);   // [[1, 2], [3, 4]]

8. Conclusion

For a list to array conversion, toArray(String[]::new) or toArray(new String[0]) returns a correctly typed copy, and mapToInt() with toArray() produces an int[] from a list of Integer.

In the other direction, Arrays.asList() is a fixed-size view of the array, List.of() and toList() are unmodifiable copies, and new ArrayList<>(Arrays.asList(array)) is the copy we can change. For primitive arrays, boxed() replaces Arrays.asList(), which would wrap the whole array as one element.

9. References

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.