Raw and Generic List - java

This is a code just to know what is wrong and what is right.
public class JavaApplication5 {
public static void main(String[] args) {
List l=new ArrayList<String>();//Line 1
List<Object> x=new ArrayList<String>();//Line 2
}
}
In the above line 1 is working fine but line 2 gives me compilation error. Can you tell me why?
Are not List and List<Object> equivalent? Either both should be wrong or both should be correct.

You have to set the same Type in the both place :
List<Object> x = new ArrayList<String>();
//----^-------------------------^--------
So you have to option to solve your problem :
One don't set any type in your ArrayList
List<Object> x = new ArrayList<>();
Or set the same type :
List<Object> x = new ArrayList<Object>();
//or
List<String> x = new ArrayList<String>();

Neither posted option. For a List of String(s), since Java 7, you can use the diamond operator - like,
List<String> x = new ArrayList<>();
However, the older
List<String> x = new ArrayList<String>();
is still legal.
Your first option is a raw type, and your second option (if it were legal) makes a List that can contain any type of Object (not just String).

Related

What is the difference List<String> list = new LinkedList<>() vs List list = new LinkedList<String>()? [duplicate]

This question already has answers here:
What is a raw type and why shouldn't we use it?
(16 answers)
Closed 3 years ago.
I found a problem when I am using java generics.
List list = new LinkedList<String>();
list.add(MyObject); //No
prompts for any compilation errors.This is not I want
If I use :
List<String> list = new LinkedList<>();
list.add(MyObject); //Prompt for compilation errors.This is what I want
I wanna know what is the difference between
List<String> list = new LinkedList<>() and
List list = new LinkedList<String>() and
List<String> list = new LinkedList<String>() and
List<String> list = new LinkedList()?
List<String> list = new LinkedList<String>(); does the following:
Declare a variable called list with type List<String>
Call the constructor of LinkedList with the type parameter String
Sets the value of list to the result of step 2.
Since a List<String> is obviously not going to be given a new LinkedList<Elephant>();, it is OK to remove the type parameter from the second part, giving: List<String> list = new LinkedList<>();. This is called "Type Inference". Java can only do this when it can calculate at compile-time what the omitted type would be.
If you use List list = new LinkedList<String>();, you do exactly the same thing as above, except your new variable list does not contain type information. This can be dangerous, as it prevents the compiler from warning/stopping you when you do something that would cause a type error.
For example:
List<String> list = new LinkedList<>();
list.add("hello"); // works fine
list.add(123); // compile-time error
I have been saved from putting an int into a list of Strings. However, if using a regular List:
List list = new LinkedList<String>();
list.add("hello"); // stil works
list.add(123); // also works
The issue with this comes from when you then retrieve items from the list:
List list = new LinkedList<String>();
list.add(123); // allowed
Object obj = list.get(0); // is obj a String? is it an int?
This breaks type safety, which is arguably a strong reason for using Java in the first place.

How to convert java ArrayList to an array?

I have an ArrayList created like this:
public class Main {
public static void main(String[] args) {
// write your code here
ArrayList list1 = new ArrayList();
list1.add(0, 5);
list1.add(1, 3.5);
list1.add(2, 10);
}
}
I am trying to create an array from it, using the toArray method:
public class Main {
public static void main(String[] args) {
// write your code here
ArrayList list1 = new ArrayList();
list1.add(0, 5);
list1.add(1, 3.5);
list1.add(2, 10);
Double[] list2 = list1.toArray(new Double[list1.size()]);
}
}
However, I am getting an error:
(Error:(16, 39) java: incompatible types: java.lang.Object[] ).
So I tried to cast the right side to double:
Double[] list2 = (Double[]) list1.toArray(new Double[list1.size()])
This time i am getting Exception in thread "main". I also tried to declare my ArrayList as double from beginning:
ArrayList<double> list1 = new ArrayList()<double>
With no success. How to do it properly? I know that my problem is probably something very basic.
The problem is that you are doing a number of things wrong:
ArrayList list1 = new ArrayList(); is incorrect because you are using a raw type. You should have gotten a compiler warning for that.
Given the previous list1.add(0, 5) is incorrect. The 5 will be boxed as an Integer because that compiler doesn't know that the list is only supposed to contain Double values.
You were getting this:
(Error:(16, 39) java: incompatible types: java.lang.Object[] ).
because you must have done something like this:
Double[] list2 = list1.toArray();
You appear to have corrected that in the code that you posted. But the no-args toArray method returns an Object[] containing the list content.
ArrayList<double> list1 = new ArrayList()<double> is incorrect because you cannot use a primitive type as a generic type parameter, and because the syntax on the RHS is wrong.
The correct version is ArrayList<Double> list1 = new ArrayList<>(); with an empty diamond.
Surprisingly, the best (most efficient) way to code the toArray is:
Double[] list2 = list1.toArray(new Double[0]);
Apparently, the implementation is able to initialize the array faster if it allocates it itself. (Or so I have heard ...)

How to add generics to my code

I need to use generics for my nestList. What syntax I can use so that both Integer and String lists can be added to nested lists as well as of any other types ?
// integer list
List<Integer> listInteger = new ArrayList<Integer>(Arrays.asList(1, 2));
// string list
List<String> listString = new ArrayList<String>(Arrays.asList("abc", "xyz"));
// nested lists.
List nestedList = new ArrayList();
nestedList.add(listInteger);
nestedList.add(listString);
nestedList.add("A");
Since you want to store lists AND non-collection objects ("A") you should store Objects in your collection, like:
import java.util.*;
public class Main {
public static void main(String[] args)
{
// integer list
List<Integer> listInteger = new ArrayList<Integer>(Arrays.asList(1, 2));
// string list
List<String> listString = new ArrayList<String>(Arrays.asList("abc", "xyz"));
// nested lists.
List<Object> nestedList = new ArrayList<Object>();
nestedList.add(listInteger);
nestedList.add(listString);
nestedList.add("A");
}
}
Just note that List<Object> is just to avoid the compiler from complaining that your collection doesn't have a type. Effectively, List<Object> and List are the same thing.
You could have suppressed the warning using this:
import java.util.*;
public class Main {
#SuppressWarnings({"rawtypes", "unchecked"})
public static void main(String[] args)
{
// integer list
List<Integer> listInteger = new ArrayList<Integer>(Arrays.asList(1, 2));
// string list
List<String> listString = new ArrayList<String>(Arrays.asList("abc", "xyz"));
// nested lists.
List nestedList = new ArrayList();
nestedList.add(listInteger);
nestedList.add(listString);
nestedList.add("A");
}
}
But ultimately, the solution in general is not good.
I don't have all your requirements, but a better idea would be to have an object to store all your collections and objects. You code would be cleaner and free from #SuppressWarnings, which are considered bad.
Something like:
MyObj myobj = new MyObj();
nestedList.setIntegers(listInteger);
nestedList.setStrings(listString);
nestedList.setSomeProperty("A");
Make the type as Object as you are adding different types of Objects(list,String) into the nestedList.
List<Object> nestedList = new ArrayList<Object>();
You can also use type as List only if you are adding list Objects in nestedList.
List<List> nestedList = new ArrayList<List>();
But this will error out if you try to add nestedList.add("A") , also It will also prompt a warning for using raw types.
Making it List<Object> = new ArrayList<>(); would allow you to add any type of Object regardless of type.
Just change this line
List<List> nestedList = new ArrayList<List>();
And it is, because you are storing list in lists, the type is List :)

Need clarification on addAll methods behaviour

Hi i am using addAll method of Collection framework. Please find below my code. It is working fine for code 1. For code 2 it is giving me compilation error. I dont know why it didnt give me error for code 1. Kindly give the reason for this.
code 1
public static void main(String[] args) {
List<Integer> firstList=new ArrayList<Integer>();
List secondList=new ArrayList(); //without generic
secondList.add("string value");
firstList.addAll(secondList);
System.out.println(firstList);
}
Output:
[string value]
Code 2
public static void main(String[] args) {
List<Integer> firstList=new ArrayList<Integer>();
List<String> secondList=new ArrayList<String>(); //with generic
secondList.add("string value");
firstList.addAll(secondList);
System.out.println(firstList);
}
Output
compilation error
Java Generics are checked on compile time. means compiler can check the generic list and can show an error if String List is to Integer. While in the first case . it is a non-generic, which compiler cannot judge at compile time.
Also read about Type Erasure
firstList.addAll(secondList);
firstList is type of string
secondList is type of numbers
In the first example you are using raw type but in the second you are using generics(specified list is for strings)
SEE HERE
If you use generics checking donet at compile time .If you use raw list it will done at runtime
List secondList=new ArrayList(); //without generic
It means List<Object> secondList=new ArrayList<Object>(); so you can add any object to this.
But if you explicitly mention the type it is clear that you can't add string to integer list, in your second case
You are trying to add all values from String bucket to a bucket which is specially allocated for Integer.
You can do like this
ArrayList commonList =new ArrayList(); // for all objects
List<String> stringList =new ArrayList<String>();
List<Integer> integerList =new ArrayList<Integer>();
stringList.add("string value");
integerList.add(1);
commonList .addAll(stringList);
commonList .addAll(integerList);
System.out.println(commonList );

How to reclaim the generic type you declared an arraylist to be in Java?

I was just playing around and a thought came to my mind and I decided I want to try it:
Make an ArrayList that holds more ArrayLists.
For example, I created an ArrayList called intList that holds ints, then filled it with values. After that I did a stringList one and filled it too. Then I made an ArrayList that holds other ArrayLists called aList and added intList and stringList to it.
Now the problem I faced was if I was retrieving objects from aList, it would not recognize if the generic type was int or string.
Here is the code I tried:
import java.util.*;
public class Practice {
public static void main(String[] args) {
List<ArrayList> list = new ArrayList<ArrayList>();
ArrayList<int> intList = new ArrayList<int>();
intList.add(1);
intList.add(2);
intList.add(3);
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("One");
stringList.add("Two");
stringList.add("Three");
list.add(intList);
list.add(stringList);
for(ArrayList lst : list) {
for(ArrayList lt : lst) {
System.out.println(lt);
}
}
}
}
Java has "generic type erasure", meaning that the type parameters to generics are "erased". Once you create an ArrayList<T> there's no way to find out what T was.
Only class types can be used as generic type parameters, so you can't have an ArrayList<int>. Use an ArrayList<Integer> instead.
In addition, the types used in your loops are wrong. Since list is a list of lists of values, lst is a list of values, which means that your lt variable will be either an integer or a string, not another ArrayList.
The deeper problem here is that you're still using raw types, so the compiler can't find that error for you. You should declare list as something like List<List<? extends Object>>. That way you can add both an ArrayList<Integer> and an ArrayList<String> to it, and extract the values as type Object within your loop.
Since no type information is stored in generic type, you could get element from sub-list and check it's type:
for(ArrayList subList : list) {
if (subList.size() > 0) {
Class elementClass = subList.get(0).getClass();
// do something else with it
}
}
But:
It will not work, if subList is empty
Generally, the concept of storing several lists of different types in another list looks rather strange.
Type erasure means that at runtime, the type is erased. That's why you can cast from one generic to another:
import java.util.ArrayList;
public class Test {
public static void main(String [] args){
ArrayList<String> list = new ArrayList<String>();
ArrayList list2 = (ArrayList)list;
list2.add(new Integer(5));
System.out.println(list2.get(0).getClass());
}
}
Will output:
class java.lang.Integer
import java.util.*;
public class Practice {
public static void main(String[] args) {
List<ArrayList<?>> list = new ArrayList<ArrayList<?>>();
ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(1);
intList.add(2);
intList.add(3);
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("One");
stringList.add("Two");
stringList.add("Three");
list.add(intList);
list.add(stringList);
for(ArrayList<?> lst : list) {
for(Object lt : lst) {
System.out.println(lt);
}
}
}
}

Categories

Resources