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 :)
Related
ArrayList<ArrayList<Integer>> treeList = new ArrayList<>();
ArrayList<Integer> aList = new ArrayList<>();
ArrayList<Integer> bList = new ArrayList<>();
aList.add(1);
treeList.add(aList);
bList = treeList.remove(0);
aList.clear(); //bList will be cleared
I know that bList and aList will refer to the same object,so when aList.clear(), bList will clear too, is there any way to make bList a new object.
... is there any way to make bList a new object.
You can copy it; e.g.
bList = new ArrayList<>(treeList.remove(0));
See How to copy Java Collections list
Actually, this looks like a case that would benefit from writing your own custom classes.
As written, your treeList is an open data structure. Anything that has access to treeList or any of its component ArrayList objects can interfere with it. That's OK in some circumstances. But if you want to protect against having different parts of your codebase "mess up" the data structure then you should put the data structure behind an abstraction boundary; e.g.
public class MyThing {
private ArrayList<ArrayList<Integer>> treeList = new ArrayList<>();
public void add(ArrayList<Integer> l){
treeList.add(new ArrayList<>(l));
}
public void remove(int index) {
return new ArrayList<>(treeList.remove(index));
}
}
Notice that MyThing carefully copies the lists when it adds them and when it removes them so that one client of the MyThing API cannot interfere with another one via shared lists.
Obviously, there is a cost in doing this.
Try this. Pass the return of the remove as an argument to the ArrayList constructor.
ArrayList<ArrayList<Integer>> treeList = new ArrayList<>();
ArrayList<Integer> aList = new ArrayList<>();
ArrayList<Integer> bList = new ArrayList<>();
aList.add(1);
treeList.add(aList);
bList = new ArrayList<>(treeList.remove(0));
aList.clear(); //bList will be cleared
System.out.println(bList);
Prints
[1]
Alternatively, instead of assigning:
bList = treeList.remove(0);
you can use List#addAll
bList.addAll(treeList.remove(0));
I'm trying to initialize a List in Java but I want to know if there's a more elegant way of initializing multiple lists with the same types.
So far I've done the following:
List<Model> list1 = new List<>();
List<Model> list2 = new List<>();
List<Model> list3 = new List<>();
But I'm trying to initialize about 10 different lists of the same type and it seems very ugly.
I've also tried doing:
List<Model> list1, list2, list3 = new List<>();
But this doesn't work.
After searching for the answer, all I could find were tips on how to initialize an array with multiple variables in one line using the asList() method but that's not what I'm trying to do.
Is this even possible?
You can use a Map where the key represents the list name and the value represents a List
Map<String,List<Model>> lists = new HashMap<>();
You can then populate the list in a for loop :
for(int i=0;i<10;++i) {
lists.put("list"+(i+1),new ArrayList<Model>());
}
You can access the lists using :
lists.get("list1").add(new Model(...));
lists.get("list2").add(new Model(...));
Disclaimer : I have not tried compiling this code since I am not on a computer.
If you have 10 lists or whatever, it's time to think: probably you need an array or list of lists.
List<List<Model>> lists = new ArrayList<>();
for(int i=0; i<10; i++) lists.add(new ArrayList<>());
// later in code instead of list5.add(...)
lists.get(5).add(...)
List is an interface (abstract type) and cannot be instantiated. You will have to use ArrayList as shown below. You can try:
List<Model> list1 = new ArrayList<Model>(), list2 = new ArrayList<Model>();
This should work as well
List<Model> list1 = new ArrayList<Model>(), list2 = new ArrayList<Model>(), list3 = new ArrayList<Model>();
The closest possible thing that you can do is following
List<Model> a = new ArrayList<>(), b = new ArrayList<>(), c = new ArrayList<>(), d = new ArrayList<>();
But either of the approach you consider has same memory consumption impact.
Here's my answer:
#SuppressWarnings({"unchecked"})
List<Model>[] lists = new List[3];
for(List list : lists) {
list = new ArrayList<Model>();
}
List<Model> list1 = lists[0];
List<Model> list2 = lists[1];
List<Model> list3 = lists[2];
Is there a way to put contents of mulitple Lists to a Set? (Eliminating the duplicates)
For example contents of listA, listB, listC all be put in a Set. (Assuming they are of same type)
You certainly can.
The Set will add all of the elements from each of the lists and then remove any duplicate objects based on the objects equals and hashCode() methods. (When implementing one, you should implement the other.)
List<Object> listA = new ArrayList<Object>();
List<Object> listB = new ArrayList<Object>();
List<Object> listC = new ArrayList<Object>();
Set<Object> set = new HashSet<Object>();
set.addAll(listA);
set.addAll(listB);
set.addAll(listC);
EDIT: Did Some Testing
Here's a little test method that shows this in action:
public static void main(final String[] args) {
final String one = new String("one");
final String two = new String("two");
final String three = new String("three");
final String four = new String("four");
final List<String> listA = new ArrayList<String>();
listA.add(one);
listA.add(two);
final List<String> listB = new ArrayList<String>();
listB.add(two);
listB.add(three);
final List<String> listC = new ArrayList<String>();
listC.add(three);
listC.add(four);
final Set<String> set = new HashSet<String>();
set.addAll(listA);
set.addAll(listB);
set.addAll(listC);
System.out.println(set);
}
And the output is:
[two, one, three, four]
This shows the implementation working, but you should obviously keep in mind that the order of the remaining objects might not be want you anticipate or desire.
Yes, you may declare a set of lists, if that's what you're looking for.
Set<List<SomeType>> mySet = new Set<>();
mySet.add(listA);
mySet.add(listB);
mySet.add(listC);
How to do that?
Following is tried code.
[Tried code]
package com.company;
import java.util.ArrayList;
import java.util.Date;
public class Main {
public static void main(String[] args) {
ArrayList<String, Integer, Date> myArray = new ArrayList<String, Integer, Date>();
myArray.add("FIRST");
myArray.add("SECOND");
myArray.add("THIRD");
// add multiple object
myArray.add(new Integer(10));
// add multiple object
myArray.add(new Date());
}
}
Yes, But not recommended.
ArrayList<Object> myArray = new ArrayList<Object>();
Taking Object as a type , it accept all the types.
ArrayList<Object> myArray = new ArrayList<Object>();
myArray.add("FIRST"); //accepted
myArray.add(new Integer(10)); //accepted
myArray.add(new Date()); //accepted
So while getting also you need to take care of which Object you are getting back.
But, good recommendation is to take that individual list's for each type.
The below line wouldn't even compile.
ArrayList<String, Integer, Date> myArray = new ArrayList<String, Integer, Date>();
What you're trying to achieve can be done using
ArrayList<Object> myArray = new ArrayList<>(); // Object type
but it is not at all a recommended option to do it. And while fetching the values back from the ArrayList, you need to handle the different types of objects manually, which is quite troublesome as well.
Therefore, it is always create ArrayList of the specific types you want to use.
ArrayList<String> myString = new ArrayList<>(); // For strings
ArrayList<Date> myDates = new ArrayList<>(); // For Date
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);
}
}
}
}