Is there any difference between these 3 lines?
List list2 = new ArrayList<String>();
List list2 = new ArrayList<>();
List list2 = new ArrayList();
As I understand, all information about generics is erased in runtime. Consequently, only type of veriable is important. So the above lines of code mean the same thing to me. If I am wrong can anybody give me some exapmle that shows the difference?
p.s. sorry for my english
While it is true that generic data is erased at compile-time, that doesn't mean they are totally useless. The only line that would compile in your example is the last one, but you would get a warning that you are using RawTypes. A RawType is a generic class that does not have a generic object. The first two lines are only half-built.
The reason you pretty much have to use generics is that the list is type-safe. If you use generics, you could use something like this:
List<String> list = new ArrayList<>();
String out = list.get(0);
If you use raw types, you would have to do this:
List list = new ArrayList();
String out = (String) list.get(0);
This may seem OK, but what if you add a value to the list that is not a String? The program crashes. For example:
List unsafe = new ArrayList();
List<String> safe = new ArrayList<>();
unsafe.add("hi");
unsafe.add(new Tree());
safe.add("hi");
safe.add(new Tree()); // This line would throw an exception.
String out = (String) unsafe.get(0);
String out1 = safe.get(0);
String out2 = (String) unsafe.get(1); // This line would throw an exception.
If you still don't quite see why to use generic types, the final nail in the coffin for raw types is this: If my (String) unsafe.get(1) is in a separate class, on the hundredth line, I know that that line is the problematic line. I, however, don't know where the non-string object is being added, only where it's being accessed.
If you use generic types, you know exactly where the problematic addition is made, and you can prevent it.
Related
Usually when generics are explains say something like this:
List<?> list = new ArrayList<?>();
This code(above) produce error because compiler doesn't know which type to instantiate.
but
List<Set<?>> list = new ArrayList<Set<?>>();
this(above) compiles good
and this:
List<Set<?>> list = new ArrayList<Set<String>>();
doesn't compile.
I am confusing about it.
Can you clarify full right to don't mess about these things.
P.S.
I know that
List<Number> list = new ArrayList<Integer>();
will not compile and I understand why.
OK. basically, this question was about to understand the difference between following two statements. According to the #DavidWallace's comment...
// good
Set<?> a_set = new HashSet<String>();
// bad
List<Set<?>> a_list = new LinkedList<Set<String>>();
Using the reference a_set, you are not allowed to add anything to the set. Thus, it's OK for a_set to reference HashSet<String>.
However, using the second reference a_list, you should be able to put any set into the list. But, the LinkedList<Set<String>> only allows the addition of the Set<String> to the list. Thus, if this were allowed, you cannot keep runtime exceptions from arising, which breaks the type safety of the system.
Limiting the question to "why doesn't this compile":
List<Set<?>> list = new ArrayList<Set<String>>();
If it did compile, it would allow this to happen:
List<Set<String>> stringSetList = new ArrayList<Set<String>>();
List<Set<?>> list = stringSetList; // compile error!
Set<Integer>() intSet = new HashSet<Integer>();
intSet.add(1);
list.add(intSet); // oops, compiles but...
Set<String> set = strings.get(0);
for (String str : set) { // Boom! ClassCastException
// expecting Strings, but got an Integer
}
For following codes:
ArrayList<String> ar = new ArrayList<String>();
ar.add(45);
And
ArrayList<String> ar = new ArrayList();
ar.add(45);
I am getting compile time error at line ar.add(45) as:
cannot find symbol
symbol : method add(int)
location: class java.util.ArrayList<java.lang.String>
al.add(45);
^
Both piece of code is failing for invalid input . Then why compiler is raising warning of unchecked or unsafe operation for second piece of code?
Then why compiler is raising warning of unchecked or unsafe operation for second piece of code?
Because you're assigning an ArrayList to a variable with type ArrayList<String>. That means that while the compiler will enforce the expectation that the array list will only contain strings when you reference that list through ar, it can't be sure that you don't have other references to the non-parameterized ArrayList that you'll use to add non-strings to it, like this:
ArrayList anythingGoes = new ArrayList();
ArrayList<String> onlyStrings = anythingGoes; // Unchecked/unsafe op
anythingGoes.add(new Date());
for (String s : onlyStrings) { // Blows up
// ...
}
Because in the second code you do not specify the type parameter of the ArrayList. You could write it in Java 7 as:
ArrayList<String> ar = new ArrayList<>();
There are two distinct issues here.
Firstly -
ArrayList<String> ar = new ArrayList();
You're telling the compiler that ar is a list of strings, but you're assigning it to a list of raw types (i.e. unbounded). Hence the compiler will warn you of an unchecked or unsafe operation. You should use something like either option below:
ArrayList<String> ar = new ArrayList<String>();
or
ArrayList<String> ar = new ArrayList<>();
(the second option is a Java 7 example and simply reduces the amount of typing you have to do. The result is the same).
Secondly -
ar.add(45);
You're adding an integer (45) into a list of strings. The compiler won't allow you to do this.
Change your generic data type as Integer
if you want to add integers
i have read on docs.oracle site that The following code snippet without generics requires casting:
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);
but if i write code with Generics then it is still prone to Error:
List<Object>= new List<Object>;
list.add("hello");
String s=(String)list.get(0);
what is then the real use of generics....:( thnx in advance..
List<Object>= new List<Object>;
list.add("hello");
String s=(String)list.get(0);
Should be
List<String>= new ArrayList<String>(); // this is now a list of String, not a list of object
^^^^^^ ^^^^^^
list.add("hello");
String s=list.get(0); // no casting needed
^
You parameterize by the type you want. Your example are 2 ways to do the same thing, since you parameterize by the most basic class.
The advantage of generics is that you can write classes that are more specific to one class, String here. This gives you better type safety to catch bugs early during compilation. This prevents issues arising from the casting approach.
Using generics makes your code Type Safe. You can prevent ClassCastException.
Suppose you want to store a list of names(string)
List listNames = new ArrayList();
listNames.add("Durgesh");//ok
But I could also add an integer to it
listNames.add(5000);//storing int instead of string
Now do this
String name2=listNames.get(1);//throws exception{int->string}
Without generics you could add invalid types to collection which could break your code.
With generics you could solve the problem
List<String> listNames = new ArrayList();
listNames.add("Durgesh");
listNames.add(3000);//would through error at compile time
So,generics provides typesafety
With List<Object> you intend to add any kind of Object.Due to Object parameter,it would allow you to add any kind of object(string,int).
Also List<x> cannot be assinged(=) to List<y> or vice versa if x can be converted to y or y can be converted to x..They both should be x or y thus providing type safety
So,you wont be able to assign(=) List<String> to List<Object> or vice versa..
Generics are used to detect runtime exceptions at compile-time itself.
Assume that you created a List to store Strings and passed it to a method.. enhanceList(List).. and after the execution, you will iterate through the list and get all strings
before genercis, it could have been possible that enhanceList(List) method will add other type of objects into the list creating possible ClassCastException
void someMethod() {
List listOfStrings = new List();
enhanceList(listOfStrings);
for(Iterator i : listOfStrings.iterator(); i.hasNext();) {
String s = (String) i.next(); //RuntimeException here
}
}
void enhanceList(List l) {
l.add(new Integer(1)); //error code
}
with generics, you can very well "bind" the type of objects the list contains
void someMethod() {
List<String> listOfStrings = new List<String>();
enhanceList(listOfStrings);
for(String s : listOfStrings) {
//no error here
}
}
void enhanceList(List<String> l) {
l.add(new Integer(1)); //compile-time error
}
However, generics should be used with caution, List<Object> doesn't help much with binding types because, it can hold any objects (since Object is super class of all the java classes). I recommend to create List of Specific type always.
Imagine having 2 Generic ArrayLists each storing different types. My program will be using only one of these ArrayLists at a time. Is it possible to create a general ArrayList (currentArrayList) which can store both ArrayLists, and use the two ArrayLists without casting.
ArrayList<Integer> arrInt = new ArrayList<>();
arrInt.add(10);
ArrayList<String> arrString = new ArrayList<>();
arrString.add("ten");
ArrayList<XXX> currentArrayList = arrInt;
Integer i = currentArrayList.get(0);
currentArrayList = arrString;
String str = currentArrayList.get(0);
Thanks.
The problem is the part where you want to:
use the two ArrayLists without casting.
Definitely not going to happen. The whole point of a static type system is to stop you from being able to treat a general type as a specific type without explicitly asking to do so.
So for example, you could say:
ArrayList<?> currentArrayList = arrInt;
Object i = currentArrayList.get(0);
But notice that i is just an Object, so the compiler is happy - we don't know anything about the things in the array except that they must be Object-based because this is a Java program. But you want to say:
ArrayList<?> currentArrayList = arrInt;
Integer i = currentArrayList.get(0);
It's that second line that isn't ever going to happen without a cast.
UPDATE Question from comments:
Can't the compiler easily infer the type of the ArrayList by
looking at the generic type of arrInt ?
Suppose it did that for us. What should it then do with the type of currentArrayList when it sees the line:
currentArrayList = arrString;
Your code as it stands assumes that the compiler is not going to do that kind of inference. Suppose you comment-out that second assignment. Now the compiler could make the inference you suggest, and allow your code to compile. But then in the future if you put back the second assignment, the rest of your code would stop compiling! This would be needlessly confusing.
You have to determine the type of the object anyway eventually.
i guess you want to avoid "supresswarning("casting")" kind of warning?
if ture, here it goes:
ArrayList<Object> list = new ArrayList<Object>();
list.add(1);
list.add("abc");
list.add(new Double(3.1415926));
list.add(true);
for (Object o : list) {
// or more accurate
String type;
if (o instanceof Integer) {
type = "int";
// logic here...
int i = (Integer) o; // no casting warning
} else if (o instanceof String) {
type = "string";
// logic here...
}
// other possibilities if you want
else { // unmatched
type = o.getClass().getSimpleName();
}
System.out.println(type + ": " + o);
}
Misunderstood the question - why on earth would you want to do that?
You are not creating a new ArrayList you are just using a Pointer without the type - its still the same ArrayList!
ArrayList<ArrayList<Object>> array = new ArrayList<ArrayList<Object>>();
array.add(new ArrayList<Integer>());
array.add(new ArrayList<String>());
This should do the trick, since all other possible Objects will inherit from Object in hence be accepted.
I'm new to Java and am trying to understand why the first code snippet doesn't cause this exception but the second one does. Since a string array is passed into Arrays.asList in both cases, shouldn't both snippets produce an exception or not produce an exception?
Exception in thread "main" java.lang.ClassCastException: java.util.Arrays$ArrayList cannot be cast to java.util.ArrayList
First snippet (causes no exception):
ArrayList<ArrayList<String>> stuff = new ArrayList<ArrayList<String>>();
String line = "a,b,cdef,g";
String delim = ",";
String[] pieces = line.split(delim);
stuff.add((ArrayList<String>) Arrays.asList(pieces));
Second snippet (causes above exception):
ArrayList<ArrayList<String>> stuff = new ArrayList<ArrayList<String>>();
String[] titles = {"ticker", "grade", "score"};
stuff.add((ArrayList<String>) Arrays.asList(titles));
If relevant, I'm using JavaSE 1.6 in Eclipse Helios.
For me (using Java 1.6.0_26), the first snippet gives the same exception as the second one. The reason is that the Arrays.asList(..) method does only return a List, not necessarily an ArrayList. Because you don't really know what kind (or implementation of) of List that method returns, your cast to ArrayList<String> is not safe. The result is that it may or may not work as expected. From a coding style perspective, a good fix for this would be to change your stuff declaration to:
List<List<String>> stuff = new ArrayList<List<String>>();
which will allow to add whatever comes out of the Arrays.asList(..) method.
If you do this, you won't get any CCE:
ArrayList<ArrayList<String>> stuff = new ArrayList<ArrayList<String>>();
String[] titles = {"ticker", "grade", "score"};
stuff.add(new ArrayList<String>(Arrays.asList(titles)));
As the error clearly states, the class java.util.ArrayList isn't the same as nested static class java.util.Arrays.ArrayList. Hence the exception. We overcome this by wrapping the returned list using a java.util.ArrayList.
The problem is you specified your List to contain ArrayLists - and by implication no other List implementations. Arrays.asList() returns its own implementation of a List based on the implementation of the array parameter, which may not be an ArrayList. That's your problem.
More broadly, you have a classic code style problem: You should be referring to abstract interfaces (ie List), not concrete implementations (ie ArrayList). Here's how your code should look:
List<List<String>> stuff = new ArrayList<List<String>>();
String[] titles = { "ticker", "grade", "score" };
stuff.add((List<String>) Arrays.asList(titles));
I have tested this code, and it runs without error.
No need to cast manually. This simple code may help you,
List stuff = new ArrayList();
String line = "a,b,cdef,g";
String delim = ",";
stuff.addAll(Arrays.asList(line.split(delim)));
Using a debugger, I determined that Array.asList(titles) returns an "Arrays$ArrayList" (ie an inner class of the Arrays class) rather than a java.util.ArrayList.
It's always best to use the interface on the left side of expressions, in this case List rather than the concrete ArrayList. This works fine:
List<List<String>> stuff = new ArrayList<List<String>>();
String[] titles = {"ticker", "grade", "score"};
stuff.add((List<String>) Arrays.asList(titles));
If you want to use your property as ArrayList<'T'> you need only declare there and create a getter.
private static ArrayList<String> bandsArrayList;
public ArrayList<String> getBandsArrayList() {
if (bandsArrayList == null) {
bandsArrayList = new ArrayList<>();
String[] bands = {"Metallica", "Iron Maiden", "Nirvana"};
bandsArrayList.addAll(Arrays.asList(bands));
}
return bandsArrayList;
}
Initializes the variable and use the method [addAll (Collection collection)](http://developer.android.com/intl/pt-br/reference/java/util/ArrayList.html#addAll(java.util.Collection))
First, Arrays.asList() should be never casted to ArrayList. Second, since generics were introduced into java programming language casting is still relevant when using legacy, pre-generics APIs.
Third, never use concrete classes at the left of assignment operator.
Bottom line, say
List<List<String>> stuff = new ArrayList<List<String>>();
String line = "a,b,cdef,g";
String delim = ",";
String[] pieces = line.split(delim);
stuff.add(Arrays.asList(pieces));
List<List<String>> stuff = new ArrayList<List<String>>();
String[] titles = {"ticker", "grade", "score"};
stuff.add(Arrays.asList(titles));
and be happy.