Why Are There Three toArray Methods in the Java Collections Framework?

Oppdatert: 24. mars 2026

The Collection interface in the Java Collections Framework contains three (yes, 3) toArray methods to extract a collection’s elements into an array. One of them has no arguments, and returns an Object array. A second one takes a lambda expression as its argument, and this lambda expression is used to generate an array of the elements’ type (say T[]). Finally, the third method takes an instance of such a typed array as its argument. If the array is large enough, it will be returned with the collection’s elements in it. Otherwise, the method uses the array as a prototype to create a new one with the right size, and returns the copy with the elements stored in it. But doesn’t this sound very complicated for something that sounds rather simple: returning an array of type T[] with the collection’s elements in it?

“Three Bridges”, based on an image generated by Google’s Gemini

It would obviously be much easier if the Collection interface simply had a toArray() method that returns an array of type T[] with the right size, no arguments needed. The problem is, however, that Java doesn’t support the creation of generic arrays. Or to be more precise: Java doesn’t support the creation of generic arrays out of nothing, but cloning goes fine. As a result, the toArray() method can’t return an array of type T[] if the collection object hasn’t seen such an array yet. And there are only two ways to guarantee the latter: either pass an array of type T[] as an argument to the method, or pass a generator method that can generate one on the fly. Otherwise, the best a toArray method can do is to put the elements in an Object array.

Java Collections Versus Arrays

Before we explore this a bit further, it’s important to remember that the whole point of the Java Collections Framework is to allow developers to work with various types of collections, like sets and lists, without ever having to deal with an array. However, there will be occasions where you do have to convert an array into a collection, or vice versa, e.g. at interfaces with other libraries. The toArray methods serve as the bridge methods for the latter, whereas e.g. the factory methods of on List and Set serve as bridge methods for the former.

Notice that one of the of factory methods on List and Set uses a variable argument. Under the hood, variable arguments are implemented using arrays, so one can wonder if they perhaps could provide the array that the toArray method needs on the other side. If the rest of the API is then carefully designed such that you can never create a collection without passing a variable argument to it, wouldn’t that solve our problem? Developers would still be working with Java collections without having to use arrays explicitly, but implicitly, they would always be there. In practice, an array of the right type would be magically created every time a collection is created, thus ensuring that the toArray has one available for cloning.

There are two answers to this question whether this would solve our problem. The first answer is yes: if you can make the entire API waterproof against constructors and factory methods not using a variable argument, this would indeed solve the problem. However, that would put a very heavy restriction on the Java Collections Framework API. Suddenly, something as simple as providing an emptyList() method or overloading the of method with regular arguments (like of(T e1) and of(T e1, T e2)) wouldn’t be possible any more. They would provide holes in the API where collections can be created without implicitly providing a typed array T[].

Generic Arrays

The root of the problem is of course, like already mentioned, that Java doesn’t allow you to create a generic array without providing another one first. But why can’t T array = new T[42] be allowed? It’s easy to understand that T t = new T() is a problem, because there’s no guarantee that when the generic type T is bound to a concrete class, there will be a constructor available with a matching signature. But that isn’t the problem for generic arrays, because all arrays are created the same way, and the ‘signature’ to create arrays is known.

The problem lies deeper. The way arrays are constructed in Java doesn’t play well with generic types. On the one hand, Java arrays store and check type information at runtime. On the other hand, for generic types, the compiler checks the type information at compile time and then erases it when the bytecode is produced. That’s why cloning a generic array works fine: the prototype array has the type information stored inside it at runtime, and can thus provide the correct type information to create a new array. But when the compiler sees an expression like new T[42], it doesn’t know yet which type will be bound to T at runtime. In fact, if using a generic type makes any sense in that part of your code, T will be bound to various classes during the execution of the code. At runtime, however, all references to T will be references to Object, which means that the JVM doesn’t have the right information available to create an array of the right type.

Be cautious though: it’s easy to find suggestions for workarounds on the internet, and these workarounds make it look like you can create a generic array. In reality, they’re still arrays of type Object[] which behave like arrays of type T[] at compile time, but not at runtime. This works fine as long as you use these arrays internally. But if you try to expose these arrays (or copies of them) as generic arrays of type T[] to the users of your class or library, a ClassCastException will follow sooner or later. And that’s exactly why the version of the toArray method without an argument has to return an Object[] array, and why the two other versions require either a prototype array or a generator function.


Why Are There Three toArray Methods in the Java Collections Framework? was originally published in Compendium on Medium, where people are continuing the conversation by highlighting and responding to this story.