List<Object> myList = new ArrayList<String>(); //(hint: no)
Map<Integer> myMap = new HashMap<int>(); // (hint: also no)
Why are the statements wrong in the above declarations?
Let's look at the first example. Think of the operations you should be able to do on a List<Object>: Add, Remove, Retrieve any Object.
You're trying to fill those requirements with a collection that you can Add, Remove, and Retrieve only strings.
List<Object> myList = new ArrayList<String>();
// This should be valid based on the List<Object> interface but obviously
// MyClass isn't String...so what would the statement do?
myList.add(new MyClass());
The second is simply because Generics in Java don't support primitive types. For more information, you could check out:
java - Why don't Generics support primitive types?
For the first one, because Java generics are not covariant. So you can't even do:
ArrayList<Object> myList = new ArrayList<String>();
For more info, see this article: Java theory and practice: Generics gotchas.
For the second one, you cannot use primitives as the generic type.
1) What would happen if anyone added a Long to the list that is referenced by myList?
2) You can't have a primitive there.
The first is impossible. You can use a wildcard:
List<?> myList = new ArrayList<String>();
But now, your list is completely unusable. Adding, removing, etc doesn't compile anymore:
myList.add(new Object()); // Error
myList.add("error"); // Error
You can't use primitives (int, double, ....) with generics. You have to use the wrapper class:
HashMap<Integer> myHap = new HashMap<Integer>();
for the second example Map has 2 generic parameters a Key and Value but the following still wont work
Map<Integer,Object> myMap = new HashMap<int,Object>();
that because as said before primitive types don't work with java generics (besides generic types always derive from Object and type erasure translates all generic variables to type Object)
For all things Java-Generics, refer to Angelika Langer. In this case, Is List<Object> a supertype of List<String>?
Even though Java does support auto-boxing, it doesn't automatically convert <int> to <Integer>. IMO this is partly to remind users that you can get nulls.
Related
What's the difference between using a typed vs. non-typedArrayList in Java?
For example, Using an ArrayList of CustomObject:
Typed:
ArrayList<CustomObject> typedArray = new ArrayList<>();
typedArray.add(new CustomObject);
or non-typed:
ArrayList<> nonTypedArray = new ArrayList<>();
nonTypedArray.add(new CustomObject);
Is there any situation where the latter is preferred? Is there any difference when the ArrayList is holding different datatypes, e.g. an ArrayList of String, Int, etc.?
In the Second Approach, it is not mandatory to add only CustomObject whereas it is in 1st Approach, otherwise, you will get Compilation Error.
ArrayList<CustomObject> typedArray = new ArrayList<>();
typedArray.add(new CustomObject());
This approach is generally preferable as there are no chances of having Class Cast Exception but in second approach there are high chances of that !!
JavaDocs explains it beautifully : Why to prefer Generics
Stronger type checks at compile time.
Elimination of casts.
Enabling programmers to implement generic algorithms.
It's never preferable to use the latter option. I don't think that is even possible. I think you meant:
ArrayList nonTypedArray = new ArrayList();
This syntax is left over from Java 1.4 and earlier. It still compiles for the purposes of backwards compatibility.
Generics was introduced in Java 1.5 which allowed you to specify the types between angled brackets.
It is always preferable to use generics because it is more type-safe.
That is, if you specify
ArrayList<String> typedArray = new ArrayList<String>();
Then you cannot accidentally add an integer to this array list; if you tried to add an integer, the program would not compile.
Of course, Generics ensures type safety at compile time. At runtime ArrayList<String> typedArray = new ArrayList<String>(); becomes ArrayList typedArray = new ArrayList();. This is to maintain backwards compatibility.
What's the difference between using a typed vs. non-typed ArrayList in
Java?
A typed/generic ArrayList is a collection of objects in which the "type" of the object is defined in angled brackets. Generics were introduced in Java 5 to create type-safe collections.
Before Generics the collection was called untyped/raw type collection because there was no way to specify the compiler the type of the collection being created.
The difference between both is to detect type-safe operations at compile time.
In both of your cases, you are adding object(s) of type 'CustomObject' to the ArrayList. There will be no issue while adding elements in the list, as both lists will consider them as typed objects.
Typed:
ArrayList<CustomObject> typedArray = new ArrayList<CustomObject>();
typedArray.add(new CustomObject);
Untyped:
ArrayList<> nonTypedArray = new ArrayList<>();
nonTypedArray.add(new CustomObject);
Is there any situation where the latter is preferred?
I don't think so. As generics are recommended to be used while creating a list to ensure type-safe operations.
Is there any difference when the ArrayList is holding different
datatypes, e.g. an ArrayList of String, Int, etc.?
Surely, there is a reasonable difference. For an untyped list, you will need to add type-cast while fetching elements from a list. As there is a possibility of the compiler throwing a ClassCastException at runtime due to different types of elements.
In runtime, there is absolutely no difference, however in compilation time, using type parameters can save you from a plethora of errors, so it is always preferable to use generics properly.
The only case where raw types are used reasonably is in legacy applications, but even in this case, you try to use typed parameters if you can.
The use of type simplifies your coding removing the need of casting and also stores your data efficiently
https://docs.oracle.com/javase/tutorial/java/generics/why.html
Yeah, I know this is an old post. But I wanted to share an instance where an untyped ArrayList is useful: when you're writing a function that supposed to act on arbitrary element types. For example, suppose you want to make a generic shuffle function that knows how to shuffle an array. Like so:
ArrayList<Die> diceRolls = getGetPossibleDiceRolls();
ArrayList<Card> cardDeck = getPossibleCards();
ArrayList<GirlToDate> blackbook = getBlackbook();
shuffle(diceRolls);
shuffle(cardDeck);
shuffle(blackbook);
.
.
void shuffle(ArrayList array) {
int size = array.size();
for (int i=0; i<size; ++i) {
int r = random.nextInt(size - i) + i;
// Swap
Object t = array.get(i);
array.set(i, array.get(r));
array.set(r, t);
}
}
Some might argue "yeah, but the proper way to do this is to create an interface or subclass of something like a Shuffleable type..." But really?
In Java 1.7 and upwards you should normally use the constructor like this:
ArrayList<MyObject> list = new ArrayList<>();
or else for a more general List object:
List<MyObject> list = new ArrayList<>();
Observe that you only specify the type <MyObject> once, not twice. This makes your code easier to maintain. The <> causes the constructor to return an ArrayList which is already typed to match the field/variable to which it is being assigned - so that no cast will be required in the calling code.
Do not use new ArrayList() as the constructor. This returns an untyped ArrayList which then has to be cast to a type to match the field/variable to which it is being assigned. This means unnecessary type checking and casting and so generally reduces performance.
recently I read a piece of code which seems weird to me. As we know, we need to initialize the generic type in collections when we need to use them. Also, we know Collections can contain Collections as their elements.
The code:
public class Solution {
public static void main(String args[]) {
ArrayList res = returnlist();
System.out.print(res.get(0));
}
public static ArrayList<ArrayList<Integer>> returnlist() {
ArrayList result = new ArrayList();
ArrayList<Integer> content = new ArrayList<Integer>();
content.add(1);
result.add(content);
return result;
}}
My question is
why can we use ArrayList result = new ArrayList(); to create an object, since we have not gave the collection the actual type of element.
why can we use result.add(content); to add a collection to a collection with collection "result" is just a plain collection. We have not defined it as a ArrayList of ArrayList
Java generic collections are not stored with a type to ensure backwards compatibility with pre J2SE 5.0. Type information is removed when added to a generic collection. This is called Type Erasure.
This means that a generic collection can be assigned to a non generic reference and objects in a generic typed collection can be placed in an non generic, nontyped collection.
All Java generics really does is make sure you can't add the wrong type to a generic list and saves you from doing an explicit cast on retrieval; even though it is still done implicitly.
Further to this
the Java section of this answer goes a little deeper into what I just said
this article also covers basically what you were asking in a more complete way
other things to watch out for with Type Erasure
Just adding up to provide summarized answer
Old way :
(A) ArrayList result = new ArrayList();
will create an Arraylist to hold "Object"
New Way :
ArrayList<Integer> content = new ArrayList<Integer>();
this represents an Arraylist which will hold "Integer" objects. This was introduced for compile-time type check purposes.
why ?
Consider the first case. Its input type is Object. We know that Object is the super class of all classes. We can pass in an Integer object, String object and so on. When fetching the data the developer has to perform proper type casting. Say if the developer initially thinks the code will accept Integer objects so he adds the following typecast while fetching the data
Integer integer=(Integer) content.get(0);
This is supposed to work. But if mistakenly he passes a String it will result in run-time error.
How it can be avoided ?
By introducing compile time checks
How it works ?
when we specify parameterized type only Integer objects can be added to the ArrayList collection. Else it will show error.
content.add(3); // will work
content.add("HARSHAD"); // error shown
If parameterized generic types are for type checking purposes how correct data can be retrieved from the list ?
The compiler implicitly performs type conversion. See the sample code
List<Integer> list=new ArrayList<Integer>();
list.add(1);
list.add(2);
Integer integer=list.get(0);
System.out.println(integer);
What the compiler actually does when you perform compilation ?
//perform type erasure
(B) List list=new ArrayList();
list.add(1);
list.add(2);
// the arraylist inturn accepts Object when you run the code
//add casting
Integer integer=(Integer)list.get(0);
Conclusion
If you see the codes (A) and (B) both are the same. Only difference is that in the second case the compiler implicitly does the same operation.
Finally to answer your question ...
ArrayList result = new ArrayList();
is allowed for backward compatibility purposes. Although this is not recommended.
Official link from Oracle docs explaining the same concept.
Generics were added to Java only in Java 5. Before that, when you use a collection, it always meant collection of objects. The old syntax is left as is for backward compatibility. So ArrayList result = new ArrayList() is actually creating an ArrayList<Object>. Since ArrayList is also an object, you can add content to the variable result.
why can we use ArrayList result = new ArrayList(); to create an object, since we have not give the collection the actual type of element.
Because java wants to it backward compatible. Generics is more of compiler feature for ensure type safety, collections can store any type of object at runtime.
Java compiler will not give you compiler error for this but it must have given you compiler warning that it is unsafe to use generic classes without type.
It may be a remnant from before generics came along to java (Java 4 or 5 I think).
This question already has answers here:
What's the difference between unbounded wildcard type List<?> and raw type List?
(4 answers)
Closed 4 years ago.
I've read alot about this, and I know that:
List<Object> listOfObject = new ArrayList<TYPE>(); // (0)
//can only work for TYPE == Object.
//if TYPE extends Object (and thus objects of type TYPE are Objects),
//this is not the same with Lists: List<Type> is not a List<Object>
Now I've read that the following is ok:
List undefinedList = new ArrayList<TYPE>(); // (1)
//works for ANY type (except for primitives)
And
List<?> wildcardList = new ArrayList<TYPE>(); // (2)
//also works for ANY type (except for primitives)
Then:
List undefinedlist = new ArrayList(); //no TYPE specified
undefinedList.add(new Integer(1)); //WORKS
undefinedList.add(new String("string")); //WORKS
However:
List<?> wildcardList = new ArrayList<TYPE>(); //TYPE specified
wildcardList.add(new TYPE(...)); //COMPILER ERROR
example:
List<?> wildcardList = new ArrayList<String>(); //TYPE specified
wildcardList.add(new String("string")); //COMPILER ERROR: The method add(capture#1-of ?) in the type List<capture#1-of ?> is not applicable for the arguments (String)
I do understand why you can't add anything to the wildcardList, since its type can be anything. However, why can you add to the undefinedList??
They seem the same & show the same behavior, given (1) and (2).
List undefinedList and List<?> wildcardList are not the same, as you discovered yourself. The first is raw type and the second is unbounded wildcard.
Use the unbounded wildcard if you want to use a generic type but you don’t know or care what the actual type parameter is. You cannot put anything (except null) into this list, and all you know about the element you get out of it is that they extend Object (actually List<?> is the same as List<? extends Object>). Unbounded wildcards are useful, because if you would declare something naively as List<Object>, you could not assign for example List<String> to it, while you can assign a List<String> to a List<?>
You should (almost) never have the need to use raw types, they are available only for compatibility with code written before Java 5.
List<?> is read as a list of some unknown type . As a programmer you can not make any assumption of what type that is and you can not put anything into such a collection other than null . But you can be rest assured that your list is type safe since the compiler will guarantee type safety for you .
List is basically called raw type . That is to say that it has opted out of type safety guaranteed by the compiler . So you can put elements of any type into that List destroying its invariants . Don't code with raw types any more . They are basically supported for backward compatibility because java was already in the second decade of development when Sun brought generics to the table and a awful lot of code was written using raw types and those programs would otherwise break.
List means that this is a list of unknown type - as such you wouldnt use it at creation time (as in your example), you'd typically use it as a method parameter. Unbound wildcards are only really useful when used as parameters in methods, such as:
public void printList(List<?> items)
This could iterate of a list of (any) unknown items. In this case List items would achieve the same purpose, but client would probably get a warning.
If you had the following:
public void printList(List<Object> items)
Then only a list of Object could be processed - not a list Strings, Integers etc. Only Objects.
Take a look at Unbounded Wildcards - it explains its pretty well
The "undefined" List contain list of type Object which is the father of all types and hence the List is not type-safe(is interconvertible)
which is why this:
List undefinedlist = new ArrayList<TYPE>(); //IS LIST OF OBJECTS
undefinedList.add(new Integer(1)); //WORKS
undefinedList.add(new String("string")); //WORKS
well.. works!
Basically, ? in the following
List<?> wildcardList = new ArrayList<TYPE>();
means some unknown (particular) type. So, it doesn't allow you add something like String, or Integer to a list of some unknown type, because generics is meant to be type-safe.
While, in the following
List<Object> listOfObject = new ArrayList<TYPE>();
you can add anything to it because everything is an Object in Java. So it's type-safe.
And also with the following
List undefinedList = new ArrayList<TYPE>();
you are telling the compiler that you don't want to use generics there. Which means every method you invoke on undefinedList will be non-generic since you have decided to use the raw List. Non-generic versions of all the containers in the collection framework were written to work for Object (which any object in Java is).
The List<?> type is generic: whatever type you put in place of the question mark will be used in the methods of the list. So you can do list.add(item) and it will only allow you to put in a String if you created a List<String>. Type-safety first.
List<String> list = new List<String>();
list.add("A"); // <-- Correct
list.add((Integer)10); // <-- Error, it is a List of Strings
The List on the other hand allows any Object to be put in there. So you can make a List, put a Giraffe in there, and later a Squid. It does not care, and could be a source of programming errors if you expect only Giraffe objects to be in there.
List list = new List();
list.add("A"); // <-- Allowed
list.add((Integer)10); // <-- Also allowed,
// but now the list contains not only strings
With the fear of sounding stupid.
Recently, I started with java/android.
I am loving it, but for the love of all that is good, I have come across an operator i can't seem to understand.
The thing is, I do not even know the name of it, so googling for it has been close to impossible. I have not found anything about it, not because it is not there, but because I do not even know where to start.
The operator is <someObject>. The same operator used in List<object>.
I actually became fascinated with it when using the AsyncTask class in android where I had to do something like
MyClass extends AsyncTask<String[], Drawable[], Drawable[]>{
...
Any info on this will be greatly appreciated.
It's not an operator - it's how you specify a generic type parameter.
It's probably best to start off with the Generics part of the Java Tutorial, then Gilad Bracha's paper, then consume the Java Generics FAQ for anything else. (There are lots of knotty corners in Java generics.)
It is not an operator, it is how you declare a parameterized type.
Before Java 5, you coulnd't say that your List was a "List of something", just a List with no type. So when you took an object out of your list, you had to cast it back to a specific type :
List strings = new ArrayList();
strings.add("hello");
String s = (String) strings.get(0);
With Java 5, you can specify the type of the elements, using angular brackets :
List<String> strings = new ArrayList<String>();
strings.add("hello");
String s = strings.get(0);
Because you know the exact type of the elements now, you don't have to cast the objects you get from the list anymore. Plus, the compiler won't let you add incompatible objects in the list :
List<String> strings = new ArrayList<String>();
strings.add(42); // Compiler error : expected a String, got an int
It's to do with generic types and type safety.
In "old java" you just had a List and it contained Objects - not type safe.
List l = new List();
l.add(new Type1()); // valid
l.add(new SomeOtherType()); // valid
These days you say
List<Type1> l = new List<Type1>();
l.add(new Type1()); // valid
l.add(new SomeOtherType()); // invalid since it is a list of Type1
The items in the List can be Type1 or any of it's subclasses.
If I understand your question, then List<Object> myList = new List<Object> means myList can hold Objects or any of its subclasses. This means myList can hold any object as they're all subclasses of Object.
Prior to Java 1.5, Java's collection classes were "untyped" (technically they still are). They could only store items that were derived from java.lang.Object. This was a bit cumbersome as you were forced to cast Object to your assumed contained type. This lead to all kinds of issues and oddities here and there.
Sun (now Oracle), added a "trick" to the language that would allow developers to specify a "type" for a container or other object. As I said, this is a "trick", the compiler performs type safety checks but in reality there is no change to the signature of the object emitted. It cleans up the code and adds a small amount of type safety but in reality its nothing more than a parlor trick.
Look up the Generics documentation provided with the JDK and the tutorials available.
How remove the:
Type safety: The expression of type
List[] needs unchecked conversion to conform to List<Object>[]
compiler warning in the following expression:
List<Object>[] arrayOfList = new List[10];
Afaik the only way is to use #SuppressWarnings("unchecked"). At least if you want to avoid the raw type warning that occurs in Matthew's answer.
But you should rethink your design. An Array of Lists? Is that really necessary? Why not a List of Lists? And if it gets too complicated (a List of List of Map of List to...), use custom data types. This really makes the code much more readable.
And as an unrelated side note: You should write List<Object>[] arrayOfList. The brackets are part of the type, not the variable.
You cannot do any variation of this without a compiler warning. Generics and arrays do not play nice. Though you can suppress it with
#SuppressWarnings("unchecked")
final List<Object> arrayOfList[] = new List[10];
List arrayOfList[] = new List[10];
or
List[] arrayOfList = new List[10];
You can't have generic arrays in Java, so there is no reason to have a reference to one. It would not be type-safe, hence the warning. Of course, you're using <Object>, which means your lists are intended to contain any object. But the inability to have generic arrays still applies.
Also, note that the second version above (with [] attached to the type) is usually considered better style in Java. They are semantically equivalent.
There are a number of ways:
You can add `#SuppressWarnings("unchecked") before the assignment to tell the compiler to ignore the warning
Use raw types List[] arrayOfList = new List[10]; notice that in Java you usually put the [] after the type not the variable when declaring it - though using raw types is discouraged by Sun since they might be removed in a future version.
Don't use arrays, it's usually a bad idea to mix collections with arrays: List<List<Object>> listOfList = new ArrayList<List<Object>>;
Unfortunately, due to the fact that generics are implemented in Java using type erasure, you cannot create an array of a type with type parameters:
// This will give you a compiler error
List<Object>[] arrayOfList = new ArrayList<Object>[10];
See this in Angelika Langer's Java Generics FAQ for a detailed explanation.
You could remove the generics and use raw types, as Matthew Flaschen shows, or use a collection class instead of an array:
List<List<Object>> data = new ArrayList<List<Object>>();