Java List parameterized? - java

I am quite new to Java ...
I wrote a class called DLPFile
which is basically a container of other objects like Strings, ints, floats, etc.
When putting my files into a List and then saving it in my session (which is from Map class) variable is easy;
DLPFile file = new DLPFile();
List <DLPFile >fileList = new ArrayList <DLPFile>();
fileList.add(file);
session.put("filesList", fileList);
but how do I retrieve the list from the session var?
When I do:
List <DLPFile files = (List) session.get("fileslist");
I got some warnings:
"List is a raw type.References to generic type List<E> should be parameterized."
I tried
List <DLPFile files = (List <DLPFile> ) session.get("fileslist");
List <DLPFile files = (List ) session.get("fileslist")<DLPFile>; and
List <DLPFile files = (List) <DLPFile> session.get("fileslist");
but none works
I suppose this is kind of a "casting" problem... (maybe?)
Thanks in advance ;)

This is because of the Generics Type erasure. The compiler has no way to determine the actual generic type argument when you get it from your session (except if you session.get takes a Class<T> argument to cast it accordingly), because the session probably only returns the type of object. You can make sure that your object is an instance of List, but the generic type information is lost (basically the compiler converts it to a List<Object> internally). That is why you get the warning, because only you as the programmer can know if the generic type parameter you want to cast it to is the right one.
If you don't like the warning you may add an
#SuppressWarnings("unchecked")
Annotation at the beginning of your method.

Are you aware that you are missing a > at the start? i.e. 'List <DLPFile files' should be 'List <DLPFile>' files'.

This option should be fine
List <DLPFile> files = (List <DLPFile>) session.get("fileslist");
Although you'll get an unchecked cast warning since I don't expect your session to be a Map<String, List<DLPFile>>.
Look through the Java Generics FAQ http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html

The first option you tried is the one you need:
List<DLPFile> files = (List<DLPFile>) session.get("fileslist");
The first warning you get doesn't have anything to do with generics: You would get the warning when casting to, for example, String as well. The compiler just tells you it can't ensure the returned object is a List<DLPFile>.
The second one, about the raw type, does have to do with generics. If you use the option above, you shouldn't get it, but if you cast to just List, you will get it. It tells you you shouldn't use List without the type parameter, in your case <DLPFile>.

As others have said, in Java you can't safely cast generic types.
Rather than ignoring the compiler, a better way to fix this problem is to put something a bit more meaningful into the session. Wrap the List in a class that handles this sort of collection of the type. Heck, even add a few instance methods that do something meaningful with the list, rather than a getFiles method.

Related

Why is Collection not simply treated as Collection<?>

Consider the following API method taken from Shiro's org.apache.shiro.subject.PrincipalCollection interface but probably present in other libraries as well:
Collection fromRealm(String realmName);
Yes even nowadays there are still libraries that are using raw-types, probably to preserve pre Java 1.5 compatibility?!
If I now want to use this method together with streams or optionals like this:
principals.fromRealm(realmName).stream().collect(Collectors.toSet());
I get a warning about unchecked conversion and using raw types and that I should prefer using parameterized types.
Eclipse:
Type safety: The method collect(Collector) belongs to the raw type Stream. References to generic type Stream<T> should be parameterized
javac:
Note: GenericsTest.java uses unchecked or unsafe operations.
As I can't change the API method's signature to get rid of this warning I can either annotate with #SuppressWarnings("unchecked") or simply cast to Collection<?> like this:
((Collection<?>) principals.fromRealm(realmName)).stream().collect(Collectors.toSet());
As this cast of course always works I'm wondering why the compilers are not simply treating Collection as Collection<?> but warn about this situation. Adding the annotation or the cast doesn't improve the code a single bit, but decreases readability or might even shadow actual valid warnings about usage of unparameterized types.
The reason is quite simple:
You may read Objects from a Collection<?> the same way as from Collection. But you can't add Objects to a Collection<?> (The compiler forbids this) whereas to a Collection you can.
If after the release of Java 5 the compiler had translated every Collection to Collection<?>, then previously written code would not compile anymore and thus would destroy the backward compatibility.
The major difference between raw type and unbounded wildcard <?> is that the latter is type safe, that is, on a compile level, it checks whether the items in the collection are of the same type. Compiler won't allow you to add string and integer to the collection of wildcard type, but it will allow you to do this:
List raw = new ArrayList();
raw.add("");
raw.add(1);
Actually, in case of unbounded wildcard collections (List<?> wildcard = new ArrayList<String>()), you can't add anything at all to the list but null (from Oracle docs):
Since we don't know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.
A Collection<?> screams:
Please don't add anything to me. I have a strict content type, ... well uh, I just forgot what type it is.
While a Collection says:
It's all cool ! You can add whatever you like, I have no restrictions.
So, why shouldn't the compiler translate Collection to Collection<?> ?
Because it would put up a lot of restrictions.
A use-case that I can think of as to why Collection is not considered as Collection<?> is let say we have a instance of ArrayList
Now if the instance is of type ArrayList<Integer> or ArrayList<Double> or ArrayList<String>, you can add that type only(type checking). ArrayList<?> is not equivalent to ArrayList<Object>.
But with only ArrayList, you can add object of any type. This may be one of the reason why compiler is not considering ArrayList as ArrayList<?> (type checking).
One more reason could be backward compatibility with Java version that didn't have generics.

Java, Generics: What's the difference between Set<?> s = HashSet<String>() and Set s = HashSet<String>()? [duplicate]

This question already has answers here:
Difference between List, List<?>, List<T>, List<E>, and List<Object>
(10 answers)
Closed 9 years ago.
I was reading about unknown types and raw types in generics, and this question came to mind. In other words, is...
Set<?> s = new HashSet<String>();
and
Set s = new HashSet<String>();
... one and the same?
I tried it out, and they both seem to accomplish the same thing, but I would like to know if they are any different to the compiler.
No, they are not the same. Here's the basic difference:
Set<?> s = HashSet<String>();
s.add(2); // This is invalid
Set s = HashSet<String>();
s.add(2); // This is valid.
The point is, the first one is a unbounded parameterized type Set. Compiler will perform the check there, and since you can't add anything but null to such types, compiler will give you an error.
While the second one being a raw type, the compiler won't do any check while adding anything to it. Basically, you lose the type safety here.
And you can see the result of loosing type safety there. Adding 2 to the set will fail at compile time for Set<?>, but for a raw type Set, it will be successfully added, but it might throw exception at runtime, when you get the element from the set, and assign it to say String.
Differences apart, you should avoid using raw types in newer code. You would rarely find any places where you would use it. Few places where you use raw type is to access static fields of that type, or getting Class object for that type - you can do Set.class, but not Set<?>.class.
The first one create a Set<?>, which means: "a generic Set of some unknown class". You won't be able to add anything to this set (except null) because the compiler doesn't know what its generic type is.
The second creates a raw, non generic set, and you can add anything you want to it. It doesn't provide any type-safety.
I don't see why you would use any of them. Set<String> should be the declared type.
The first one uses generics and the second one uses the raw form of Set.
The first one uses a wildcard as the generic type parameter. It means, "a Set of some specific yet unknown type", so you won't be call methods such as add that take a generic parameter, because the compiler doesn't know which specific type it really is. It maintains type safety by disallowing such a call at compile time.
The raw form removes all generics and provides no strong typing. You can add anything to such a Set, even non-Strings, which makes the following code not type-safe:
Set<String> genericSet = new HashSet<String>();
Set rawSet = genericSet;
rawSet.add(1); // That's not a String!
// Runtime error here.
for (String s : genericSet)
{
// Do something here
}
This would result in a runtime ClassCastException when the Integer 1 is retrieved and a String is expected.
Maintaining as much generic type information as possible is the way to go.
Set<String> s = HashSet<String>();
Set<?> tells the compiler that the set contains a specific type, but the type is unknown. The compiler uses this information to provide errors when you attempt to invoke a method with a generic parameter, like add(T).
Set tells the compiler that the set is a "raw" type, where no generic type parameter is given. The compiler will raise warnings, rather than errors, when the object's generic methods are invoked.
In order to add elements to the set without warnings, you need to specify the generic type information on the variable. The compiler can infer the type parameters for the constructor. Like this:
Set<String> s = new HashSet<>();
This information allows the compiler to verify that the Set is used in a type safe way. If your code compiles without type safety warnings, and you don't use any explicit casts, you can be assured that there will be no ClassCastException raised at runtime. If you use generics, but ignore type safety warnings, you might see a ClassCastException thrown at a point where you don't have a cast in your source code.

List and List<?> in Java

What is the difference between List and List<?>? I know I can't add any element to the List<?>. I have a code:
List<String> myList = new ArrayList<String>();
processList(myList);
processListGeneric(myList);
public static void processList(List myList) {
Iterator it = myList.iterator();
while(it.hasNext())
System.out.println(it.next());
}
public static void processListGeneric(List<?> myList) {
Iterator<?> it = myList.iterator();
while(it.hasNext())
System.out.println(it.next());
}
The name of the two methods cannot be the same, because it causes compile time error. So is there any difference in these two approaches?
Both do the same, but in second case compiler is informed that you really want a list with no type bounds and raises no warnings. If you are working with Java 5 or later you are encouraged to use second approach.
The difference is that you can't add anything to a List<?>, since it's a List of an unknown type.
For example, you are prevented from doing this:
List<Integer> listOfInt = new ArrayList<Integer>();
List<?> list = listOfInt;
list.add("hello?"); // Compile-time error
You can add anything you want to the base type List since the type of the list items is not checked.
List<?> (pronounced "collection of unknown")is a collection whose element type matches anything. It's called a wildcard type for obvious reasons.
Refer to the following code
List<String> myList = new ArrayList<String>();
myList.add("John");
String name = myList.get(0);
System.out.println(name); //print John
List<?> myListNew = myList;
myListNew.add("Sam");//Compile time error
String nameNew = myListNew.get(0);//Compile time error
Object newName = myListNew.get(0);
System.out.println(newName);//Prints John
Since we don't know what the element type of myListNew stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.
On the other hand, given a List<?>, we can call get() and make use of the result. The result type is an unknown type, but we always know that it is an object. It is therefore safe to assign the result of get() to a variable of type Object or pass it as a parameter where the type Object is expected.
List is raw type and List< ?> is wildcard type. Take look http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
Both of them behave same. Using parametrized notation you are just avoiding any warnings in Java5 and above. You cannot have both the syntax in same java file because due to type erasure compiled unit has two methods with exactly same signature in same class file and thus violating language rules.
Following is what you would be getting from compiler:
Method processList(List) has the same erasure processList(List) as another method in type ...
Just writing List without a type parameter is deprecated, but otherwise the same as writing List<Object>. So the question becomes "What's the difference between List<Object> and List<?> and which one should I use?".
As you already know, you can't add (anything other than null) to a List<?>, so if you need to add to a list, you should use a List<Object> (or a more specific type where applicable, of course). On the other hand, a method that takes a List<Object>, only accepts List<Object>s and not any lists that contain a subclass of Object. That is, it would not accept a List<String>. If the method takes a List<?> however, it accepts any kind of list. So if you don't need to add to the list, you should use List<?> as it is more general.
The second method uses generics (introduced in Java 5).
One important distinction is the <?> represents a single type, not any object like this:
List<? extends Object> myList
So you could say that using the first method (without the wildcard syntax) is more flexible, as you'd be able to add any object to your List. Although, you'll get a (compiler) warning that you declaration should be parameterized.
Using the <?> unbounded wildcard syntax will avoid the warning, but you're telling the compiler it could be a list of any type, instead of actually using generics to enforce type safety. You are strongly encouraged to use generics to assist you in making your application type safe.
If, for example, you know that the list should only ever contain String objects, declare it thus:
List<String> myList
Then you'll avoid unnecessary casting of use of the instanceof operator, etc.
Here's a brief tutorial on generics in Java, for your information:
http://javarevisited.blogspot.co.uk/2011/09/generics-java-example-tutorial.html

What are the implications of casting a generic List to a non-generic List?

I'm refatoring a home-grown DAO container, hoping to make the class generic. It internally uses an ArrayList to store the retrieved objects.
One usage of this class puts the container's list into a request scope, and due to a limitation of Websphere, I can't pass the generic List<Foo> to the request scope (Websphere doesn't handle generics out-of-the-box)
If I go ahead with my refactorings, I will need to convert/cast the List<Foo> into a non-generic List object..
// Boils down to this...
List<Foo> listFoo = new FooListing().findAllFoo();
List listThings = listFoo;
request.setAttribute("listThings", listThings);
What are the implications of reversing a generification like this? Should I avoid doing this kind of manipulation?
EDIT: The code snippet is verbose to explicitly demonstrate what I'm describing..
If the component type of the List does match the expected type, there is no problem.
Generics in Java are only used for type-checks by the compiler, they have not effect at runtime. If you are using an older library that does not support generics, you have no choice but to ignore the generic type.
Things should continue to work, as this system has been designed with backwards compatibility in mind.
So all you are losing is the compile-time type checking (it puts you back to where Java was at 1.4, which means, if the types match, everything will work, if not, you'll get ClassCastExceptions or other unwanted behaviour at runtime).
However, I think you can just write
request.setAttribute("listThings", listFoo);
This method takes any kind of Object. Even if it wanted a List, you could still pass a List<Foo> (which is still a List).
Java uses "type erasure" for generics -- essentially that means that the compiler checks the generics, but the runtime forgets all about it and just treats it as a list of objects.*
Whenever you treat a List<Foo> as just a List, you won't get compiler checks to make sure you don't put a Bla into your list. So you could get a ClassCastException if you call List<Foo>.get() and it turns out to be a Bla hiding in the list. But that can only happen if you some code puts a Bla in your list.
If you wan't to be cautious, then if you pass the List<Foo> as a List to anything that might add a non-Foo to the list, don't treat it as a List<Foo> whenever you access it, but treat it as a list of Objects and add instanceof checks.
*Some of the information is accessible at runtime, but let's not complicate matters.
A "non-generic" version of a generic type is called a "raw type".
Passing a generic type where the raw equivalent is requested is generally ok. This is actually the main reason generics in Java work the way they do (with erasure): to enable interoperability between "generified" code and pre-generics code.
The main thing you need to be careful about is that if you pass a List<Foo> to something that askes for a List, they may put non-Foo objects into the List. You won't get any compile time checking to help you here. You do get some runtime checks: a ClassCastException will be thrown when you use a method that returns a Foo on your List<Foo> and it has to return a non-Foo.
If you want more fail-fast behavior you can wrap your List<Foo> with Collections.checkedList() to get a List that'll check the type of elements on insertion.
Things get more complicated if Foo itself is a generic type. Runtime checks are only done on reified types (ie: the type with generic type parameters removed) so if you give them a List<Set<Bar>> and they insert a Set<Baz> or just a Set, you won't know since the runtime/reified type of the element is Set either way.
First, you can't cast a generic to a non-generic list so yeah you'd have to convert it.
Second, the two main advantages to a generic list are 1) it ensures that all objects are of the specified type and 2) it allows you to directly access methods of the object collection without needing to recast them. This allows you to write cleaner code and saves some processing cycles from having to cast back and fourth.
Neither one of these advantages is a dire need however. If you can't use them you won't notice a difference in performance. Your code may look a little messier though.
I have similar problems with Weblogic Portal. Just use none-generic type for this case.

Converting non-generic List type to Generic List type in Java 1.5

I have a List that is guaranteed to contain just one type object. This is created by some underlying code in a library that I cannot update. I want to create a List<ObjectType> based on the incoming List object so that my calling code is talking to List<ObjectType>.
What's the best way to convert the List (or any other object collection) to a List<ObjectType>.
When inter-operating with legacy code that doesn't specify type parameters for generic types, use a wildcard. For example, suppose you are calling a method in an older library that simply returns a raw Collection:
Collection getItems();
In your code, assign the result to a variable declared with a wildcard:
Collection<?> items = widget.getItems();
This way, you preserve type safety so you won't get any warnings.
The legacy code might specify (in a comment, most likely) what the generic parameters should be. For example:
/**
* #return the items, as a Collection of {#link Item} instances.
*/
Collection getItems();
In this case, you have a choice. You can cast the result to a Collection<Item>, but if you do so, you are relying 100% on the third-party library, and discarding the assurance of Java generic types: that any ClassCastException raised at runtime will occur right at an explicit cast.
What if you don't fully trust the third-party library, but still need to produce a Collection<Item>? Then create a new collection, and add the contents after casting them to the expected type. That way, if there is a bug in the library, you find out about it right away, rather than having some code far away and much later mysteriously blow up with a ClassCastException.
For example:
Collection<?> tmp = widget.getItems();
Collection<Item> items = new ArrayList<Item>(tmp.size());
for (Object o : tmp)
items.add((Item) o); /* Any type error will be discovered here! */
For a case where the type parameter isn't known at compile-time, you can use the type-checked collection factories of the Collections class.
You can simply cast the list:
List raw = new ArrayList();
List<String> generic = (List<String>) raw;
The best and safest way is to use java.util.Collections method 'checkedList(List list, Class type)'
With this method, all of the items in your old List will be checked as early as possible.
If you just cast to List<T> in any old place you will get an "unchecked" compiler warning. We resolved that by moving it to a utility method.
public class Lists {
#SuppressWarnings({"unchecked"})
public static <T> List<T> cast(List<?> list) {
return (List<T>) list;
}
}
Caller now gets no warning, e.g.:
for (Element child : Lists.<Element>cast(parent.getChildren())) {
// ...
}
That checkedList utility is in theory a great idea, but in practice it sucks to have to pass in the class you expect. I hope Java will get runtime generic typing information eventually.
Try this:
List<ObjectType> objectsWithType = Arrays.asList((ObjectType[])wildcardObjects).toArray());
But remember that this will produce a fixed length List. If you try to add or remove element from this list, it will throw an error. So be always careful while using Arrays.asList().

Categories

Resources