Could java.util.ArrayList<T>.toArray() be made friendlier? - java

I'm surprised by how painful it is to use java.util.ArrayList<T>.toArray().
Suppose I declare my array list as:
java.util.ArrayList<double[]> arrayList = new java.util.ArrayList<double[]>();
... add some items ...
Then to convert it to an array, I have to do one of the following:
double[][] array = (double[][])arrayList.toArray(new double[0][]);
or:
double[][] array = (double[][])arrayList.toArray(new double[arrayList.size()][]);
or:
double[][] array = new double[arrayList.size()];
arrayList.toArray(array);
None of the above are very readable. Shouldn't I be able to say the following instead?
double[][] array = arrayList.toArray();
But that gives a compile error because Object[] can't be converted to double[][].
Perhaps it's not possible because toArray has to return Object[]
for backwards compatibility with pre-template days.
But if that's the case, couldn't a friendlier alternative method be added
with a different name? I can't think of a good name, but almost anything
would be better than the existing ways; e.g. the following would be fine:
double[][] array = arrayList.toArrayOfNaturalType();
No such member function exists, but maybe it's possible to write a generic helper function that will do it?
double[][] array = MyToArray(arrayList);
The signature of MyToArray would be something like:
public static <T> T[] MyToArray(java.util.ArrayList<T> arrayList)
Is it possible to implement such a function?
My various attempts at implementing it resulted in compile errors
"error: generic array creation" or "error: cannot select from a type variable".
Here's the closest I was able to get:
public static <T> T[] MyToArray(java.util.ArrayList<T> arrayList, Class type)
{
T[] array = (T[])java.lang.reflect.Array.newInstance(type, arrayList.size());
arrayList.toArray(array);
return array;
}
It's called like this:
double[][] array = MyToArray(arrayList, double[].class);
I wish the redundant final parameter wasn't there, but, even so,
I think this is the least-horrible way that I've seen so far for converting array list to array.
Is it possible to do any better than this?

Is it possible to do any better than this?
Nope.
None of the above are very readable. Shouldn't I be able to say the following instead?
double[][] array = arrayList.toArray();
It would be nice ... but you can't.
The problem is that the toArray() method was specified way back in Java 1.2 with the behavior you are seeing. Generic types were not added to the language until Java 1.5. When they were added, the designers chose the "type erasure" approach, for compatibility with earlier versions of Java. So:
the semantics of the toArray() methods could not be changed without breaking compatibility, and
type erasure makes it impossible for a toArray() method implementation to know what the list's actual element type is, so it could not get it right anyway.

Unfortunately you cannot write
double[][] array = arrayList.toArray();
The reason is that toArray() was defined in JDK 1.2 (prior to generics) to return Object[]. This cannot be changed compatibly.
Generics were introduced in Java 5 but were implemented using erasure. This means that the ArrayList instance has no knowledge at runtime of the types of objects it contains; therefore, it cannot create an array of the desired element type. That's why you have to pass a type token of some sort -- in this case an actual array instance -- to tell ArrayList the type of the array to create.
You should be able to write
double[][] array = arrayList.toArray(new double[0][]);
without a cast. The one-arg overload of toArray() is generified, so you'll get the right return type.
One might think that it's preferable to pass a pre-sized array instead of a throwaway zero-length array. Aleksey Shipilev wrote an article analyzing this question. The answer is, somewhat counterintuitively, that creating a zero-length array is potentially faster.
Briefly, the reason is that allocation is cheap, a zero-length array is small, and it's probably going to be thrown away and garbage collected quickly, which is also cheap. By contrast, creating a pre-sized array requires it to be allocated and then filled with nulls/zeroes. It's then passed to toArray(), which then fills it with values from the list. Thus, every array element is typically written twice. By passing a zero-length array to toArray(), this allows the array allocation to occur in the same code as the array filling code, providing the opportunity for the JIT compiler to bypass the initial zero-fill, since it knows that every array element will be filled.
There is also JDK-8060192 which proposes to add the following:
<A> A[] Collection.toArray(IntFunction<A[]> generator)
This lets you pass a lambda expression that is given the array size and returns a created array of that size. (This is similar to Stream.toArray().) For example,
// NOT YET IMPLEMENTED
double[][] array = arrayList.toArray(n -> new double[n][]);
double[][] array = arrayList.toArray(double[][]::new);
This isn't implemented yet, but I'm still hopeful this can get into JDK 9.
You could rewrite your helper function along these lines:
static <T> T[] myToArray(List<T> list, IntFunction<T[]> generator) {
return list.toArray(generator.apply(list.size()));
}
(Note that there is some subtlety here with concurrent modification of the list, which I'm ignoring for this example.) This would let you write:
double[][] array = myToArray(arrayList, double[][]::new);
which isn't terribly bad. But it's not actually clear that it's any better than just allocating a zero-length array to pass to toArray().
Finally, one might ask why toArray() takes an actual array instance instead of a Class object to denote the desired element type. Joshua Bloch (creator of the Java collections framework) said in comments on JDK-5072831 that this is feasible but that he's not sure it's a good idea, though he could live with it.
There an additional use case here as well, of copying the elements into an existing array, like the old Vector.copyInto() method. The array-bearing toArray(T[]) method also supports this use case. In fact, it's better than Vector.copyInto() because the latter cannot be used safely in the presence of concurrent modification, if the collection's size changes. The auto-sizing behavior of toArray(T[]) handles this, and it also handles the case of creating an array of the caller's desired type as described above. Thus, while adding an overload that takes a Class object would certainly work, it doesn't add much over the existing API.

Related

Why is there no toArray(Class<T>)?

Why is there no toArray variant in List which only accepts a type, for example:
Foo[] array = list.toArray(Foo.class);
// or
Foo[] array = list.toArray(Foo[].class);
I have seen
// existing array
Foo[] array = list.toArray(array);
// Fake array
Foo[] array = list.toArray(new Foo[0]);
But it seems inefficient and counter-intuitive to me to create an empty array when I just want to specify the type and not create an unecessary throw-away array.
From an interface-perspective, I agree.
The method only needs the type (apart from the side-effects), so it would be appropriate to only demand the type.
The main reason is efficiency, I guess. The implementation that only takes the type is significantly slower, I did not check the implementation details though (see the benchmarks in .toArray(new MyClass[0]) or .toArray(new MyClass[myList.size()])? and the blog Arrays of Wisdom of the Ancients).
However, note that we got a new variant since Java 11 which comes closer to what you want and is also more appropriate in this situation:
toArray(Foo[]::new)
From its documentation:
Returns an array containing all of the elements in this collection, using the provided generator function to allocate the returned array.
Use toArray() to create an array whose runtime type is Object[], or use toArray(T[]) to reuse an existing array.
The default implementation calls the generator function with zero and then passes the resulting array to toArray(T[]).
The method does not need reflection since you provide the generator directly.
To summarize, nowadays you should use
toArray() if you want Object[] (rarely appropriate),
toArray(T[]) if you want to reuse an existing array (should be large enough),
toArray(IntFunction<T[]>) if you want type safety and a new array.

Creating a Generic array without using Arraylist

In order to complete one of my Java assignments, I have to do what seems like the impossible.
I have to create a method that takes in different stuff and plugs it into an array. We don't necessarily know what is being put into the array and thus the array must be able to accept Strings, Double, Integer, etc...
Of course, the obvious solution would be to use ArrayList<E> (i.e. a generic array). However, that's partly the complication of the problem. We cannot use an ArrayList, only a regular array. As far as I can find, when creating an array its intake value must be declared. Which leads me to believe that this assignment is impossible (yet I doubt the teacher would give me an impossible assignment).
Any suggestions?
You can always use an array of Object - Object[].
Object[] objects = new Object[2];
objects[0] = "ABC";
objects[1] = Integer.valueOf("15");
Are you sure you need a generic array or an array that can hold anything?
If the former, then create a class that will act as wrapper of Object[] array and use a <T> generic for type cast when getting the elements of the array, which is similar to the implementation of ArrayList class. If the latter, use Object[] directly.

Java return array versus pass by reference

I'm designing an API function of a class which will return an array for client to use.But I'm not quite sure whether I should make it a return value or make it as an argument of the function.See below:
Method I:
MyObject[] getMyObject() {... return someObject;}
Method II:
void getMyObject(MyObject[] someObject) {...//assign value to someObject[index]};
In Android API I saw it is very common to return a List<MyObject> or Set<MyObject>. Does it indicate Method I is better? So what are the pros and cons of these two methods in Java?
Update: In method II I mean to assign value to someObject[index], not someObject. My question is not regarding "does Java pass reference or value". It's just simply comparing two feasible way of doing things.
Arrays are not resizeable. So with method 1, you can create a new array with just the right size and return that. With method 2, if the incoming array is the wrong size, you're sunk.
Java does not have pass-by-reference. So assigning something to someObject in method 2 won't do anything for the caller. You can only alter the elements of someObject.
Both ways have advantages and disadvantages.
Version #1
MyObject[] getMyObject() {... return someObject;}
Pros:
This allows you to return an arbitrary number of results.
It is arguably easier for the caller.
Cons:
The called method has to allocate an array. (Alternatively, it has to manage / recycle arrays, which is going to be difficult to do in general. Note that reusing a static array is liable to make the method non-reentrant, etcetera.)
Version #2
void getMyObject(MyObject[] someObject) {...//assign value to someObject[index]};
Pros:
This is potentially better in terms of objects allocated because the caller will be in a better position to recycle / reuse the array.
It allows you to pass values in ... if that is a requirement.
Cons:
The caller has to provide the array, which makes the method more work to use.
The called method has no control over the array size. That means that there is a potential error case if the supplied array is too small ...
There is also a third way, where an array is passed and returned. If the array size is not correct (or maybe if a null is passed) the called method allocates or reallocates an array. The result is either the original array or the reallocated array.
Which is better?
IMO, the first version is better under most circumstances because it is easiest to get right. IMO, you should only consider the alternatives in an API design if there is a demonstrable need to minimize new object allocation. (If you are coding for a Hotspot Java implementation or equivalent, new object allocation is cheap ...)
Finally, a simpler / cleaner way than all of the above is to use a Collection rather than a bare array. Using a standard Collection type allows you to avoid the messiness of preallocating something of the correct size.
Return is more natural to write and read, also pass by "reference" as you call it has more complications than meets the eyes..
someObject[i] = a; //works
someObject = a; // doesnt work
Java has one parameter passing mechanism: everything is passed by value, not by reference.
It's subtle, but true. The implications matter.
You can certainly return any time from that method, be it array, List, or Set. You may or may not be able to alter the contents of the List or Set, because the implementation underneath might have been made unmodifiable by the developer who wrote the method.
Personally, I tend to prefer the collections over arrays. They are more expressive than raw arrays. If I get a Set back, I know that all the entries are unique in some way.

Using Java List when array is enough

Is it advisable to use Java Collections List in the cases when you know the size of the list before hand and you can also use array there? Are there any performance drawbacks?
Can a list be initialised with elements in a single statement like an array (list of all elements separated by commas) ?
Is it advisable to use Java Collections List in the cases when you know the size of the list before hand and you can also use array there ?
In some (probably most) circumstances yes, it is definitely advisable to use collections anyway, in some circumstances it is not advisable.
On the pro side:
If you use an List instead of an array, your code can use methods like contains, insert, remove and so on.
A lot of library classes expect collection-typed arguments.
You don't need to worry that the next version of the code may require a more dynamically sized array ... which would make an initial array-based approach a liability.
On the con side:
Collections are a bit slower, and more so if the base type of your array is a primitive type.
Collections do take more memory, especially if the base type of your array is a primitive type.
But performance is rarely a critical issue, and in many cases the performance difference is not relevant to the big picture.
And in practice, there is often a cost in performance and/or code complexity involved in working out what the array's size should be. (Consider the hypothetical case where you used a char[] to hold the concatenation of a series. You can work out how big the array needs to be; e.g. by adding up the component string sizes. But it is messy!)
Collections/lists are more flexible and provide more utility methods. For most situations, any performance overhead is negligible.
And for this single statement initialization, use:
Arrays.asList(yourArray);
From the docs:
Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.) This method acts as bridge between array-based and collection-based APIs, in combination with Collection.toArray. The returned list is serializable and implements RandomAccess.
My guess is that this is the most performance-wise way to convert to a list, but I may be wrong.
1) a Collection is the most basic type and only implies there is a collection of objects. If there is no order or duplication use java.util.Set, if there is possible duplication and ordering use java.util.List, is there is ordering but no duplication use java.util.SortedSet
2) Curly brackets to instantiate an Array, Arrays.asList() plus generics for the type inference
List<String> myStrings = Arrays.asList(new String[]{"one", "two", "three"});
There is also a trick using anonymous types but personally I'm not a big fan:
List<String> myStrings = new ArrayList<String>(){
// this is the inside of an anonymouse class
{
// this is the inside of an instance block in the anonymous class
this.add("one");
this.add("two");
this.add("three");
}};
Yes, it is advisable.
Some of the various list constructors (like ArrayList) even take arguments so you can "pre-allocate" sufficient backing storage, alleviating the need for the list to "grow" to the proper size as you add elements.
There are different things to consider: Is the type of the array known? Who accesses the array?
There are several issues with arrays, e.g.:
you can not create generic arrays
arrays are covariant: if A extends B -> A[] extends B[], which can lead to ArrayStoreExceptions
you cannot make the fields of an array immutable
...
Also see, item 25 "Prefer lists to arrays" of the Effective Java book.
That said, sometimes arrays are convenient, e.g. the new Object... parameter syntax.
How can a list be initialised with elements in a single statement like an array = {list of all elements separated by commas} ?
Arrays.asList(): http://download.oracle.com/javase/6/docs/api/java/util/Arrays.html#asList%28T...%29
Is it advisable to use Java Collections List in the cases when you know the size of the list before hand and you can also use array there ? Performance drawbacks ???
If an array is enough, then use an array. Just to keep things simple. You may even get a slightly better performance out of it. Keep in mind that if you...
ever need to pass the resulting array to a method that takes a Collection, or
if you ever need to work with List-methods such as .contains, .lastIndexOf, or what not, or
if you need to use Collections methods, such as reverse...
then may just as well go for the Collection/List classes from the beginning.
How can a list be initialised with elements in a single statement like an array = {list of all elements separated by commas} ?
You can do
List<String> list = Arrays.asList("foo", "bar");
or
List<String> arrayList = new ArrayList<String>(Arrays.asList("foo", "bar"));
or
List<String> list = new ArrayList<String>() {{ add("foo"); add("bar"); }};
Is it advisable to use Java
Collections List in the cases when you
know the size of the list before hand
and you can also use array there ?
Performance drawbacks ?
It can be perfectly acceptable to use a List instead of an array, even if you know the size before hand.
How can a list be initialised with
elements in a single statement like an
array = {list of all elements
separated by commas} ?
See Arrays.asList().

Java Convert Generic LinkedList to Generic Array

So for starters lets say that I have a LinkedList<String>,
I can easily convert it to an array via toArray(). i.e.
LinkedList<String> strList = new LinkedList<String>();
String[] strArray = strList.toArray(new String[0]);
But Lets say I have a LinkedList<T>
Then I the following code:
LinkedList<T> tList = new LinkedList<T>();
T[] strArray = tList.toArray(new T[0]);
I get the Cannot create a generic array of T error message.
How can I get around this?
Specifically in my class I have LinkedList<AbstractNode<T>> nodes, and I am trying to implement a getAll() method that returns all the nodes as an Array.
Thanks!
Note Péter Török's answer provides the correct answer to my problem, but for me simply returning an ArrayList instead of [] as Bar mentioned, ended up smoothing my code out a lot.
Note2 after looking at my code a bit more i'm not even sure if any conversion was necessary to begin with, LinkedList was fine for what I was trying to do... :-/
A workaround which is used in the class library would be (using an unchecked cast)
public <T> T[] toArray(List<T> list, T[] a) {
if (a.length < list.size()) {
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), list.size()));
}
return list.toArray(a);
}
or, with a Class parameter instead of an array:
public <T> T[] toArray(List<T> list, Class<T> k) {
return list.toArray(
(T[])java.lang.reflect.Array.newInstance(k, list.size()));
}
From Java Generics and Collections, chapters 6.4-5.
Inability to create generic arrays is one of the most serious restrictions in Java. Because it is so annoying, it is worth reiterating the reason it occurs: generic arrays are problematic because generics are implemented via erasure, but erasure is beneficial because it eases evolution.
The best workaround is to use ArrayList or some other class from the Collections Framework in preference to an array. We discussed the tradeoffs between collection classes and arrays in Section 2.5, and we noted that in many cases collections are preferable to arrays: because they catch more errors at compile time, because they provide more operations, and because they offer more flexibility in representation. By far, the best solution to the problems offered by arrays is to "just say no": use collections in preference to arrays.
Sometimes this won't work, because you need an array for reasons of compatibility or efficiency. Examples of this occur in the Collections Framework: for compatibility, the method toArray converts a collection to an array [...]
[...] a naïve method to convert a collection to an array will not work. The first fix we might try is to add an unchecked cast, but we will see shortly that this leads to even more perplexing problems. The correct fix will require us to resort to reflection.
Since Java generic is really replaceing your T with type object and casting to concrete type resolved at compilation, there is possible to create List<T>, but not T[]. (First one will be list of objects, second one is unknown)
Well reflection allows you to do many ugly hacks. You can use them. Personally I use them only if there is no other ways to do something. I don't like runtime errors.
But my question is: Do you REALLY needs T[], why don't you use ArrayList<T> instead?

Categories

Resources