Java ArrayList declarations - java

I'm currently studying for the Java OCA exam and came across a question relating to ArrayList declarations.
Which of the following is valid?:
1. ArrayList al1 = new ArrayList();
2. ArrayList al2 = new ArrayList<>();
3. ArrayList<> al3 = new ArrayList<>();
4. ArrayList<Double> al4 = new ArrayList<>();
5. ArrayList<Double> al5 = new ArrayList<Float>();
According to my book, answers 1,2 and 4 are valid. Answers 3 and 5 are invalid.
However, no proper explanation is given. All it does is show the standard way to declare an ArrayList:
ArrayList<E> al3 = new ArrayList<E>();
and mentions that it's also valid to declare the ArrayList without the generic part.
I'm also unable to find a decent article on this topic online. Can someone explain (or point me in the direction of a good article) the different permutations above?
Thanks in advance.

1 is valid in all versions of Java
Here you are declaring the ArrayList without using Generics. This means regardless of what you add to the arraylist, when you get it back out it will be of type Object and will require casting to a type. This is the old way of using Collections in Java 1.4 (pre generics) and is supported for backwards compatibility. Nowadays you should always use Generics.
2 and 4 are valid in Java 7 only
The empty brackets: <> are Java7's new Type inference that means you don't have to specify the type twice. Note Java7, it wont work in older versions.
So in Java7
ArrayList<Double> al4 = new ArrayList<>();
Is the same as
ArrayList<Double> al4 = new ArrayList<Double>();
This link has more info on type inference: http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html
3 is invalid because if you are using Generics you must specify a type in the variable declaration.
5 is invalid because if you declare a List with type Double you cannot then assign it a List that is of Type Float, you can only assign it a list of type Double.
So this would be valid:
ArrayList<Double> al5 = new ArrayList<Double>();

Below 2 will be valid only in Java SE7. Java SE7 allows type inference so you don't need to provide type inside <>again.
ArrayList<Double> al4 = new ArrayList<>();
ArrayList al2 = new ArrayList<>();
On the other hand below one is valid on all Java versions; this is to ensure backward compatibility of non-generic code.
ArrayList al1 = new ArrayList();
Below is not allowed as Collection of Float is not a sub type of collection of Double. Moreover Float is not subtype of Double; so no question of it being a valid declaration.
Note that even array version doesn't compile.
Double[] dd = new Float[5]; //won't compile
ArrayList<Double> al5 = new ArrayList<Float>(); //won't compile
Below one is not a valid declaration.
ArrayList<> al3 = new ArrayList<>();

Related

About ArrayList and Generic Type [duplicate]

This question already has answers here:
What is the point of the diamond operator (<>) in Java?
(7 answers)
What is a raw type and why shouldn't we use it?
(16 answers)
Closed 5 years ago.
1. First: What is the difference between
ArrayList<Class> myList = new ArrayList<Class>();
ArrayList<Class> myList = new ArrayList<>();
2. Second:
If i declare myList like this:
ArrayList myList = new ArrayList<Integer>();
Why this still work: myList.add("A String!!");
but NOT work with this declaration:
ArrayList<Integer> myList = new ArrayList<>();
There is no difference in the first two. The second one is short version of the first one added in java 7 (I think)
In the second thing you declare a generic java list (the declaration doesn't say it is integer list). Then you give that variable an instance of ArrayList. This is something you do runtie and is not in the declaration. That's why the code compiles (you can add a string because the instance of array list can be anything). But it will fail at runtime because in that current run the instance is list of Integers.
When you declare it ArrayList myList then it knows compile time that this list can have only integers and compilation fails.
To your first question:
What is the difference between
ArrayList<Class> myList = new ArrayList<Class>();
ArrayList<Class> myList = new ArrayList<>();
There is no difference. In the second case, you let the compiler through type inference decide the type.
To your second question:
If I declare myList like this:
ArrayList myList = new ArrayList<Integer>();
Why this still work: myList.add("A String!!");
but NOT work with this declaration:
ArrayList<Integer> myList = new ArrayList<>();
You are using a raw type in the first case. This is kind of like using Object as generic type, only worse. You forego all compile-time type checking and thus you will encounter an Exception in your example.

List-type explanation

Perhaps a bit misleading title, but not sure how to word it.
In the example of an ArrayList, what are the differences between these two list-objects:
ArrayList list = new ArrayList<Integer>();
and
ArrayList<Integer> list = new ArrayList();
Note: I know about the list hierarchy, interfaces and inheritance, but I am not sure how it applies in this situation. Can anyone please help me clear this up?
ArrayList list = new ArrayList<Integer>();
will give a warning about using the raw ArrayList object since you are not specifing the list is of a generic ArrayList type.
ArrayList<Integer> list = new ArrayList();
will give an unchecked conversion warning since you are assigning a non-generic ArrayList to a typed ArrayList
ArrayList<Integer> list = new ArrayList<>();
will work in java7+. The diamond operator tells the compiler to infer the generic type.
List<Integer> list = new ArrayList<Integer>();
is the standard way of using an ArrayList even it is more long winded than the new java7 syntax.

Non-generic object of generic type

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

Can we have an Array of a collection?

I was trying create an array of a collection as follows.
ArrayList<Integer> ar[]=new ArrayList<Integer>[50];
but it gives me an error -> generic array creation
can anybody explain me why is it?
You can't create arrays of generic types. Use collection of collections instead:
ArrayList<ArrayList<Integer>> = new ArrayList<ArrayList<Integer>>();
Why can't we create an array of generic type? Array stores they exact type internally, but due to the type erasure at runtime there will be no generic type. So, to prevent you from been fooled by this (see example below) you can't create an array of generic type:
//THIS CODE WILL NOT COMPILE
ArrayList<Integer>[] arr = new ArrayList<Integer>[5];
Object[] obj = arr;
obj[0] = new ArrayList<Long>(); //no one is safe
ArrayList is internally a 1D array itself. what you need 2D array so you can create
ArrayList<Integer[]> ar=new ArrayList<Integer[]>();
or
ArrayList<ArrayList<Integer>> = new ArrayList<ArrayList<Integer>>();
The answer to you question can be found in the Java Language Specification. You are trying to create an array using Array Creation Expression. It says the following: "It is a compile-time error if the ClassOrInterfaceType does not denote a reifiable type". Because arrays in Java are created at runtime, their type information should be completely available at runtime. In other words array element type should be a reifiable type. Generics in Java are implemented using type erasure (i.e. only subset of generics compile-time type information is available at runtime) hence they are not reifiable by definition and therefore you cannot create arrays of generic types.
Actually you can have an Array of Collection, it just is not allowed that the Collection has a specific type.
You can do something like
ArrayList<?>[] ar = new ArrayList<?>[50];
// or ArrayList[] ar = new ArrayList[50];
ar[0] = new ArrayList<Integer>();
but you will not have the benefits of Generics - there is no type information for the content of the Collection, you will need to cast when reading from it
Integer i = (Integer) ar[0].get(0);
You could do something like this
ArrayList<Integer> ar[]= new ArrayList[50];
ArrayList<Integer> intArr = new ArrayList<Integer>();
ArrayList<Long> longArr = new ArrayList<Long>();
ar[0]=intArr;
ar[1]= longArr; // compile error Type mismatch: cannot convert from ArrayList<Long> to ArrayList<Integer>
You can have an array "technically" of type ArrayList but its a bit nit picky. Create it as an ArrayList<ArrayList<Integer>> list = ArrayList<ArrayList<Integer>(); and convert it using toArray(ArrayList<Integer>[list.size()]);.
Example:
ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
list.add(new ArrayList<Integer>());
list.add(new ArrayList<Integer>());
list.add(new ArrayList<Integer>());
int count = 1;
for(ArrayList<Integer> AList: list) {
for(int i = 0; i < 4; i++)
AList.add(count++);
}
ArrayList<Integer>[] check = list.toArray(new ArrayList[list.size()]);
for(ArrayList<Integer> AL : check) {
for(Integer i:AL) {
System.out.print(i + " ");
}
System.out.println();
}
Output:
1 2 3 4
5 6 7 8
9 10 11 12
Works and is an ArrayList array

Initialize an Array of ArrayList [duplicate]

This question already has answers here:
How can I create an Array of ArrayLists?
(20 answers)
Closed 9 years ago.
How can I initialize an Array of ArrayList<String>?
I tried this syntax but it didn't work:
ArrayList<String>[] subsection = new ArrayList<String>[4];
you can define like this :
ArrayList<String>[] lists = (ArrayList<String>[])new ArrayList[10];
lists[0] = new ArrayList<String>();
lists[0].add("Hello");
lists[0].add("World");
String str1 = lists[0].get(0);
String str2 = lists[0].get(1);
System.out.println(str1 + " " + str2);
That syntax works fine for the non-generic ArrayList. (ideone)
But it won't work for the generic ArrayList<E>: (ideone)
This code:
ArrayList<String>[] subsection = new ArrayList<String>[4];
Gives a compiler error:
Main.java:8: generic array creation
ArrayList<String>[] subsection = new ArrayList<String>[4];
For the generic version use an ArrayList<ArrayList<E>>:
ArrayList<ArrayList<String>> subsection = new ArrayList<ArrayList<String>>();
Okay after comment, I thought well... your right why not.
Figured it out.
ArrayList[] test = new ArrayList[4];
test[3] = new ArrayList<String>();
test[3].add("HI");
System.out.println(test[3].get(0));
Though I will be honest, I am not really sure WHY this works.
Once you assign the first item of test as a new Collection, it will only allow all other items in the array to be that type. So you couldn't do
test[3] = new ArrayList<String>();
test[2] = new HashSet<String>();
Look into generics as type clarification process, you can assign typed value to a variable of raw type AND vice versa. In core generics are a shortcut for the programmers to avoid making type casting too much, which also helps to catch some logical errors at compile time.
At the very basics ArrayList will always implicitly have items of type Object.
So
test[i] = new ArrayList<String>(); because test[i] has type of ArrayList.
The bit
test[3] = new ArrayList<String>();
test[2] = new HashSet<String>();
did not work - as was expected, because HashSet simply is not a subclass of ArrayList. Generics has nothing to do here. Strip away the generics and you'll see the obvious reason.
However,
test[2] = new ArrayList<String>();
test[3] = new ArrayList<HashSet>();
will work nicely, because both items are ArrayLists.
Hope this made sense...

Categories

Resources