aspose file tools*
The moose likes Java in General and the fly likes How do you create an array of typesafe-collections? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "How do you create an array of typesafe-collections?" Watch "How do you create an array of typesafe-collections?" New topic
Author

How do you create an array of typesafe-collections?

Jeffrey Bennett
Greenhorn

Joined: May 17, 2004
Posts: 12
Example:
final ArrayList<String>[] arr;
arr = ...
arr[0] = new ArrayList<String>();
arr[1] = new ArrayList<String>();


The question is, how should the "arr" variable be constructed.

=====================
Intuitively:
arr = new ArrayList<String>[2];

This yields a compiler error:
Cannot create a generic array of ArrayList<String>

------------------------------
If you use this:
arr = new ArrayList[2];

The error disappears, but you then get the typesafe warning (in Eclipse):
The expresion of type ArrayList[] needs unchecked conversion to conform to ArrayList<String>[]

Not sure if this warning is from Eclipse or from Java, but is there a way to construct 'arr' that compiles and is warning-free?
Jean-Francois Briere
Ranch Hand

Joined: Mar 03, 2004
Posts: 101
Generics and arrays don't mix well. This is one of the zillion problems with generics.
You could create a helper method to do generic array creation for lists without any warning (by suppressing it):

Then it would be easy to use it whereever in your code:

Regards
Joni Salonen
Ranch Hand

Joined: Jan 07, 2006
Posts: 53
Originally posted by Jean-Francois Briere:
[QB]Generics and arrays don't mix well. This is one of the zillion problems with generics.


Actually, I think it's rather a problem with arrays; as you probably know, their type safety has been broken since day 1.
A better solution to the problem would be ditching the array and using some List implementation. If it suits your needs, of course.
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
Indeed, I see it as a problem with arrays, the covariance was a mistake.
Jesper de Jong
Java Cowboy
Saloon Keeper

Joined: Aug 16, 2005
Posts: 14347
    
  22

When I first encountered this problem, I wrote a blog entry about it: http://www.bloggingaboutjava.org/cms/wordpress/2006/01/java-generics-quirks/ where I explained in more detail why you can't create an array of a generic type.

There's just no way around this, you'll have to use something else than an array.


Java Beginners FAQ - JavaRanch SCJP FAQ - The Java Tutorial - Java SE 8 API documentation
Jeffrey Bennett
Greenhorn

Joined: May 17, 2004
Posts: 12
Thanks all. I was trying to avoid the @SuppressWarnings hack. Converting to List<ArrayList<String>> seems to be the right move for me.

Thanks again.
Tony Morris
Ranch Hand

Joined: Sep 24, 2003
Posts: 1608
Originally posted by Jeffrey Bennett:
Thanks all. I was trying to avoid the @SuppressWarnings hack. Converting to List<ArrayList<String>> seems to be the right move for me.

Thanks again.


It cannot be achieved - you can even provide mathematical proof of this.
I notified the JSR14 team well before public release (back when I was working on the implementation) but, being the unorthodox member of the Java community working for a large corporation of monkeys, it was largely ignored by The Elite.


Tony Morris
Java Q&A (FAQ, Trivia)
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Tony, are you saying that

List<ArrayList<String>>

wouldn't work as expected (as an alternative to the array)?


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Tony Morris
Ranch Hand

Joined: Sep 24, 2003
Posts: 1608
Originally posted by Ilja Preuss:
Tony, are you saying that

List<ArrayList<String>>

wouldn't work as expected (as an alternative to the array)?


I don't think so (depends on what you mean by "work").
It is easy to point out that prior to 1.5, any Collection was convertible to an array. This statement no longer holds as a general absolute truth (assuming a compile-time warning is illegitimate).

For your case (List<ArrayList<String>> , it definitely does not hold - try it - convert to an array without a compile-time warning - you cannot. Another perspective - it is impossible to implement java.util.ArrayList without a compile-time warning/suppression. There are some other profound broken parts of generics (I'm surprised that someone was able to hide them in 400+ pages - a feat on its own!). The most alarming defect comes down to an inherent contradiction (reductio ad absurdum) that occurs far more often than the collection/array problem (which also comes down to a contradiction).

It can be stated like so:
* Any type T that is now parameterised (say T<E> that declares a reference prior to 1.5 is declared T and since 1.5, is declared T<?>. In other words what was once a List is now a List<?>.
* If some type T that is now parameterised contains a method with at least one parameter whose type is deduced (directly or indirectly) from the type parameter, it is impossible (compile-time error) to invoke that method without "using" the value of the type parameter (in which case, you get a compile-time warning).
* Java is reverse compatible.

The contradiction lies in the fact that one of these statements must be untrue. I claim it is the last one though you are free to pick and choose (by redefining "Java" for example).

List.add is one such example. It takes an argument whose type is derived from the type parameter of List (directly in this case). It was once possible to invoke this method without using the value of the type parameter (i.e. you could invoke it with anything). This is now impossible (given that a List is now a List<?> .

You might be tempted to suggest that "it makes no sense to invoke List.add unless you know the value of the type parameter anyway" - but this is not completely relevant. It is not "knowing" the value of the type parameter that matters, it is the fact that even if you did "know it", you have no way to use it. And even if you did "know it", the cast to say List<T> may as well contain a concrete reference type for T, since even if you use some supertype of T, the cast will fail at runtime. Simply, given any List<?> a cast to List<Object> may fail. Or, given a List<Sub> a cast to List<Super> will fail. The analogous statement never held prior to 1.5. That is, given any List, you could always use its "contents" as references of type Object (or some supertype given some other known). It could be quite plausibly argued that the introduction of generics increases the possibility for cast failures!!

Try it, given a List<?>, invoke add - good luck But when you fail, don't conclude the analysis - I encourage one to look a little deeper - deeper than the JSR-14 expert group too
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
Originally posted by Tony Morris:
I don't think so (depends on what you mean by "work").


It would appear they mean work as in using it in place of an array. Aside from syntactic sugar and covariance I don't see why it wouldn't.

Originally posted by Tony Morris:
It is easy to point out that prior to 1.5, any Collection was convertible to an array. This statement no longer holds as a general absolute truth (assuming a compile-time warning is illegitimate).


I fail to see how this is true. Collection.toArray() still works.

Originally posted by Tony Morris:
For your case (List<ArrayList<String>> , it definitely does not hold - try it - convert to an array without a compile-time warning - you cannot.


No warning.



Originally posted by Tony Morris:
Another perspective - it is impossible to implement java.util.ArrayList without a compile-time warning/suppression. There are some other profound broken parts of generics (I'm surprised that someone was able to hide them in 400+ pages - a feat on its own!).


It can't be implemented because arrays are covariant, granted, but I'm not sure what 400+ pages you're referring to. A book or something to do with the JSR?

Originally posted by Tony Morris:
The most alarming defect comes down to an inherent contradiction (reductio ad absurdum) that occurs far more often than the collection/array problem (which also comes down to a contradiction).

It can be stated like so:
* Any type T that is now parameterised (say T<E> that declares a reference prior to 1.5 is declared T and since 1.5, is declared T<?>. In other words what was once a List is now a List<?>.
* If some type T that is now parameterised contains a method with at least one parameter whose type is deduced (directly or indirectly) from the type parameter, it is impossible (compile-time error) to invoke that method without "using" the value of the type parameter (in which case, you get a compile-time warning).
* Java is reverse compatible.

The contradiction lies in the fact that one of these statements must be untrue. I claim it is the last one though you are free to pick and choose (by redefining "Java" for example).


Either I misunderstand or disagree with your second point. What do you mean by "using the value of the type parameter"? If the parameterized type is declared I can invoke methods that use it without a warning.

Originally posted by Tony Morris:
List.add is one such example. It takes an argument whose type is derived from the type parameter of List (directly in this case). It was once possible to invoke this method without using the value of the type parameter (i.e. you could invoke it with anything). This is now impossible (given that a List is now a List<?> .


Yes and is this necessarily a bad thing? I'm not convinced that being able to add anything to any List is good.

Originally posted by Tony Morris:
You might be tempted to suggest that "it makes no sense to invoke List.add unless you know the value of the type parameter anyway" - but this is not completely relevant. It is not "knowing" the value of the type parameter that matters, it is the fact that even if you did "know it", you have no way to use it. And even if you did "know it", the cast to say List<T> may as well contain a concrete reference type for T, since even if you use some supertype of T, the cast will fail at runtime. Simply, given any List<?> a cast to List<Object> may fail. Or, given a List<Sub> a cast to List<Super> will fail. The analogous statement never held prior to 1.5. That is, given any List, you could always use its "contents" as references of type Object (or some supertype given some other known). It could be quite plausibly argued that the introduction of generics increases the possibility for cast failures!!


I read this a few times and I don't know what you're getting at. A List<Sub> is not a List<Super> and talking about a cast from one to the other is nonsense. There is no cast, it's an unchecked conversion. If such a "cast" were to happen at runtime it would be from List to List and it would not fail. Furthermore you an use the contents of any list as references of type Object or any other supertype. It's trivial:



Not particularly difficult and there's no compile-time warning and the cast will not fail. If you're talking about adding an Object to the List, then yes it's true you can't treat it as a List of Objects. I don't consider that a bad thing though. Yeah, sure you could treat it that way prior to 1.5, but it also meant my code was cluttered with casts every time I wanted to do something meaningful with that List, like pull an Integer from it.

Originally posted by Tony Morris:
Try it, given a List<?>, invoke add - good luck But when you fail, don't conclude the analysis - I encourage one to look a little deeper - deeper than the JSR-14 expert group too


Why in the world would I want to add something to a List that contains God only knows what? If that's the case, declare it as a List<Object> and you can very well do that. I can understand alot of your rants but this one is all over the place and doesn't make much sense at all.
Tony Morris
Ranch Hand

Joined: Sep 24, 2003
Posts: 1608

List<ArrayList<String>> list = new ArrayList<ArrayList<String>>();
Object[] array = list.toArray();

Sorry, I meant a typed array.
Given list, you cannot convert it to a ArrayList<String>[]. Furthermore, you can declare a reference of type ArrayList<String>[] but you cannot assign to anything but null. This also affects methods that accept variable argument lists - you cannot invoke a method with a variable argument list if that list has type parameters (without a warning). e.g. method(List<String>...)

I will reconsider how to reword the remainder - it seems you have fallen into the trap that I tried to mitigate - perhaps not very well.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: How do you create an array of typesafe-collections?