Pass by value trouble with java's list add method - java

ArrayList<ArrayList<String>> list1 = new ArrayList<ArrayList<String>>();
ArrayList<String> list2 = new ArrayList<String>();
list2.add("foo");
System.out.println(list2); //[foo]
list1.add(list2);
System.out.println(list1); //[[foo]]
list2.set(0, "bar");
System.out.println(list2); //[bar]
System.out.println(list1); //[[bar]]
The code above shows 2 lists. When I add list2 (containing foo) to list1 they both now contain foo. But when I modify list2 to bar, list1 will change as well. I've always thought the add method only gives a copy of list2 to list1 and what I do to list2 will not change for list1.
How can I make it that I add list2 to list1 but allow list2 to be freely modified in the future so list1 will not be affected again?

In Java references are passed by value, not the object referenced. This means that list2.add(list1); cannot alter the reference list1 but it takes a reference to the same object and if you change that it is visible.
The way you should write this is
List<List<String>> list1 = new ArrayList<List<String>>();
List<String> list2 = new ArrayList<String>();
list2.add("foo");
System.out.println(list2); //[foo]
list1.add(new ArrayList<String>(list2)); // take a copy of the list.
System.out.println(list1); //[[foo]]
list2.set(0, "bar");
System.out.println(list2); //[bar]
System.out.println(list1); //[[foo]]
or
list1.add(list2);
list2 = new ArrayList<String>();
list2.add("bar");
System.out.println(list2); //[bar]
System.out.println(list1); //[[foo]]
My example above is simple but my actual problem is buried in nested loops and such.
List<List<String>> list1 = new ArrayList<List<String>>();
for(some loop) {
List<String> list2 = new ArrayList<String>();
// populate list2, can be smaller than the previous list2 !!
list1.add(list2);
}

How about list1.add(list2.clone()); ?
This will create a copy of list2 (allocate memory, clone contents etc) and put reference to it in list1.

You should clone every item and add to a new list.

Related

ArrayList<ArrayList>> is backedup by the ArrayList that is being added

I am creating an ArrayList of ArrayList and adding ArrayLists to it. But everytime I make changes to the ArrayList, it is being reflected in the ArrayList<ArrayList>.
Example:
List<List<String>> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<String>();
list2.add("Cat");
list1.add(list2); //no problem
list2.clear();
list2.add("Dog");
list1.add(list2); //problem! the cat is replaced by two dogs this time!!
How do I make sure that updates to list2 is not reflected in list1?
Short answer ... replace
list2.clear();
with
list2 = new ArrayList<String>();
The problem is happening because list1.add(list2) adds a reference to list2 to list1. It is NOT making a copy of the list that list2 refers to, at any point. So you end up adding multiple references to the same list object to list1.
This is a consequence of the way that Java argument passing works, and the way that the collection APIs have all been designed to work.
What I've observed from the following equivalent but runnable program:
import java.util.List;
import java.util.ArrayList;
public class Test1 {
public static void main(String[] args){
List<ArrayList<String>> list1 = new ArrayList<ArrayList<String>>();
ArrayList<String> list2 = new ArrayList<String>();
list2.add("Cat");
System.out.println(list2);
list1.add(list2);
System.out.println(list1);
list2.clear();
System.out.println(list2);
list2.add("Dog");
System.out.println(list2);
list1.add(list2);
System.out.println(list2);
System.out.println(list1);
if(list1.get(0) == list1.get(1)) {
System.out.println("Lists at position 0 and 1 are the same");
}
}
}
it's not that "the cat is replaced by two dogs" as you wrote in a comment of your code but that, at the end, i.e. after the last statement, list1 contains two lists, each of them containing a "Dog".
This is of course due to the fact that when you add list2 to list1 the second time, you're not adding actually a new list, but the same one. You probably thought that by clearing the list2 and then adding it again would add a new list with a new item "Dog", but what you actually did was modifying the same object and adding the same reference. Remember that list2 and list1 are references!
What you need to do is create a new ArrayList object, like:
ArrayList<String> list3 = new ArrayList<String>();
list3.add("Dog");
list1.add(list3);
instead of clearing list2 and adding it again.
Check also these articles:
Why can't you have a "List<List<String>>" in Java?
Working with a List of Lists in Java
What are classes, references and objects?

Error: generic array creation with my own object

I want to create a list that contains linked list of MyObject.
LinkedList<MyObject>[] list = new LinkedList<MyObject>[n];
But it shows:
Main.java:19: error: generic array creation LinkedList<MyObject>[] list = new LinkedList<MyObject>[n];
How can I create this kind of list?
Why are you trying to create an array of LinkedLists? it is after all already a List.
Change your code to
List <MyObject> list = new LinkedList<MyObject>();
if you want a collection of these LinkedLists then I suggest that you create a new List
List <LinkedList<MyObject>> theBigList = new ArrayList <> ();
and then you can add to this list
theBigList.add (list);
A List of Lists would look like:
List<List<MyObject>> listList = new LinkedList<>();
List<MyObject> list1 = new LinkedList<>();
List<MyObject> list2 = new LinkedList<>();
listList.add(list1);
listList.add(list2);
List<MyObject> list3 = listList.get(0);
And an Array of LinkedLists would look like:
#SuppressWarnings("unchecked")
List<MyObject>[] listArray = new LinkedList[n];
List<MyObject> list1 = new LinkedList<>();
List<MyObject> list2 = new LinkedList<>();
listArray[0] = list1;
listArray[1] = list2;
List<MyObject> list3 = listArray[0];
Both assume the diamond operator (<>) which is a Java 7 shortcut, but can be replaced with the full type (new LinkedList<MyObject> for the second and LinkedList<List<MyObject>> for the first case).
And the fact that arrays cannot be instantiated of generic type (due to all kinds of weird internals). See for example http://bugs.java.com/bugdatabase/view_bug.do?bug_id=5105887

Adding elements from a List to a List of Lists

I trying to write some code in Java - I have two Lists:
List<List<Integer>> listOfLists;
List<Integer> listOfIntegers;
I want to add each of the Integers in listOfIntegers to a new element (List) in listOfLists, then I need to clear listOfIntegers
I tried:
listOfLists.add(listOfIntegers);
listOfIntegers.clear();
but this clears the reference to the List in listOfLists
Thanks to Manuel Silva I came up with what I need:
List<Integer> newList = new ArrayList<>();
for (Integer i : lineIntegersList)
{
newList.add(i);
}
listOfLists.add(newList);
lineIntegersList.clear();
You could do something like this...
ArrayList<ArrayList<String>> listOlists = new ArrayList<ArrayList<String>>();
ArrayList<String> singleList = new ArrayList<String>();
singleList.add("hello");
singleList.add("world");
listOlists.add(singleList);
ArrayList<String> anotherList = new ArrayList<String>();
anotherList.add("this is another list");
listOlists.add(anotherList);
thanks #tster - here you instantiate your "parent list" and as you would know how to do - just create a child list to add to the parent.. :D
for (Integer i: listOfIntegers) {
List<Integer> list = new LinkedList<Integer>();
list.add(i);
listOfLists.add(list);
}
This solution basically adds a new List with one element for each integer in the list of integer to the initial list of list

Copying from one list to another

I have a list of sets of pairs. If I use equal does it copy every set over?
List<HashSet<Pair>> list1 = new ArrayList<HashSet<Pair>>();
List<HashSet<Pair>> list2 = new ArrayList<HashSet<Pair>>();
list1.add(0, new HashSet<Pair>());
list1.add(1, new HashSet<Pair>());
list1.add(2, new HashSet<Pair>());
list1.add(3, new HashSet<Pair>());
If I do list2 = list1, does it copy over perfectly? Because when I use it, it crashes.
Iterator<Pair> it1 = list2.get(0).iterator();
Iterator<Pair> it2 = list2.get(1).iterator();
Iterator<Pair> it3 = list2.get(2).iterator();
Iterator<Pair> it4 = list2.get(3).iterator();
list2 = list1
This assignment simply assigns the reference list2 to point at the same List as list1. (Note that there is only one list with two references to it.) If you want to copy the list, you need to use a copy constructor:
list2 = new ArrayList<HashSet<Pair>>(list1);
No. The assignment doesn't copy anything, and instead updates the list2 reference to point to list1. So you are able to use list2 as if it were list1; however changes you make to 2 will be reflected in 1.

How to make a new List in Java

We create a Set as:
Set myset = new HashSet()
How do we create a List in Java?
List myList = new ArrayList();
or with generics (Java 7 or later)
List<MyType> myList = new ArrayList<>();
or with generics (Old java versions)
List<MyType> myList = new ArrayList<MyType>();
Additionally, if you want to create a list that has things in it (though it will be fixed size):
List<String> messages = Arrays.asList("Hello", "World!", "How", "Are", "You");
Let me summarize and add something:
JDK
1. new ArrayList<String>();
2. Arrays.asList("A", "B", "C")
Guava
1. Lists.newArrayList("Mike", "John", "Lesly");
2. Lists.asList("A","B", new String [] {"C", "D"});
Immutable List
1. Collections.unmodifiableList(new ArrayList<String>(Arrays.asList("A","B")));
2. ImmutableList.builder() // Guava
.add("A")
.add("B").build();
3. ImmutableList.of("A", "B"); // Guava
4. ImmutableList.copyOf(Lists.newArrayList("A", "B", "C")); // Guava
Empty immutable List
1. Collections.emptyList();
2. Collections.EMPTY_LIST;
List of Characters
1. Lists.charactersOf("String") // Guava
2. Lists.newArrayList(Splitter.fixedLength(1).split("String")) // Guava
List of Integers
Ints.asList(1,2,3); // Guava
In Java 8
To create a non-empty list of fixed size (operations like add, remove, etc., are not supported):
List<Integer> list = Arrays.asList(1, 2); // but, list.set(...) is supported
To create a non-empty mutable list:
List<Integer> list = new ArrayList<>(Arrays.asList(3, 4));
In Java 9
Using a new List.of(...) static factory methods:
List<Integer> immutableList = List.of(1, 2);
List<Integer> mutableList = new ArrayList<>(List.of(3, 4));
In Java 10
Using the Local Variable Type Inference:
var list1 = List.of(1, 2);
var list2 = new ArrayList<>(List.of(3, 4));
var list3 = new ArrayList<String>();
And follow best practices...
Don't use raw types
Since Java 5, generics have been a part of the language - you should use them:
List<String> list = new ArrayList<>(); // Good, List of String
List list = new ArrayList(); // Bad, don't do that!
Program to interfaces
For example, program to the List interface:
List<Double> list = new ArrayList<>();
Instead of:
ArrayList<Double> list = new ArrayList<>(); // This is a bad idea!
First read this, then read this and this. 9 times out of 10 you'll use one of those two implementations.
In fact, just read Sun's Guide to the Collections framework.
Since Java 7 you have type inference for generic instance creation, so there is no need to duplicate generic parameters on the right hand side of the assignment:
List<String> list = new ArrayList<>();
A fixed-size list can be defined as:
List<String> list = Arrays.asList("foo", "bar");
For immutable lists you can use the Guava library:
List<String> list = ImmutableList.of("foo", "bar");
//simple example creating a list form a string array
String[] myStrings = new String[] {"Elem1","Elem2","Elem3","Elem4","Elem5"};
List mylist = Arrays.asList(myStrings );
//getting an iterator object to browse list items
Iterator itr= mylist.iterator();
System.out.println("Displaying List Elements,");
while(itr.hasNext())
System.out.println(itr.next());
List is just an interface just as Set.
Like HashSet is an implementation of a Set which has certain properties in regards to add / lookup / remove performance, ArrayList is the bare implementation of a List.
If you have a look at the documentation for the respective interfaces you will find "All Known Implementing Classes" and you can decide which one is more suitable for your needs.
Chances are that it's ArrayList.
List is an interface like Set and has ArrayList and LinkedList as general purpose implementations.
We can create List as:
List<String> arrayList = new ArrayList<>();
List<String> linkedList = new LinkedList<>();
We can also create a fixed-size list as:
List<String> list = Arrays.asList("A", "B", "C");
We would almost always be using ArrayList opposed to LinkedList implementation:
LinkedList uses a lot of space for objects and performs badly when we have lots of elements.
Any indexed operation in LinkedList requires O(n) time compared to O(1) in ArrayList.
Check this link for more information.
The list created by Arrays.asList above can not be modified structurally but its elements can still be modified.
Java 8
As per doc, the method Collections.unmodifiableList returns an unmodifiable view of the specified list. We can get it like:
Collections.unmodifiableList(Arrays.asList("A", "B", "C"));
Java 9
In case we are using Java 9 then:
List<String> list = List.of("A", "B");
Java 10
In case we are at Java 10 then the method Collectors.unmodifiableList will return an instance of truly unmodifiable list introduced in Java 9. Check this answer for more info about the difference in Collections.unmodifiableList vs Collectors.unmodifiableList in Java 10.
List list = new ArrayList();
Or with generics
List<String> list = new ArrayList<String>();
You can, of course, replace string with any type of variable, such as Integer, also.
The following are some ways you can create lists.
This will create a list with fixed size, adding/removing elements is not possible, it will throw a java.lang.UnsupportedOperationException if you try to do so.
List<String> fixedSizeList = Arrays.asList(new String[] {"Male", "Female"});
List<String> fixedSizeList = Arrays.asList("Male", "Female");
List<String> fixedSizeList = List.of("Male", "Female"); //from java9
The following version is a simple list where you can add/remove any number of elements.
List<String> list = new ArrayList<>();
This is how to create a LinkedList in java, If you need to do frequent insertion/deletion of elements on the list, you should use LinkedList instead of ArrayList
List<String> linkedList = new LinkedList<>();
As declaration of array list in java is like
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
There is numerous way you can create and initialize array list in java.
1) List list = new ArrayList();
2) List<type> myList = new ArrayList<>();
3) List<type> myList = new ArrayList<type>();
4) Using Utility class
List<Integer> list = Arrays.asList(8, 4);
Collections.unmodifiableList(Arrays.asList("a", "b", "c"));
5) Using static factory method
List<Integer> immutableList = List.of(1, 2);
6) Creation and initializing at a time
List<String> fixedSizeList = Arrays.asList(new String[] {"Male", "Female"});
Again you can create different types of list. All has their own characteristics
List a = new ArrayList();
List b = new LinkedList();
List c = new Vector();
List d = new Stack();
List e = new CopyOnWriteArrayList();
One example:
List somelist = new ArrayList();
You can look at the javadoc for List and find all known implementing classes of the List interface that are included with the java api.
Sometimes - but only very rarely - instead of a new ArrayList, you may want a new LinkedList. Start out with ArrayList and if you have performance problems and evidence that the list is the problem, and a lot of adding and deleting to that list - then - not before - switch to a LinkedList and see if things improve. But in the main, stick with ArrayList and all will be fine.
Using Google Collections, you could use the following methods in the Lists class
import com.google.common.collect.Lists;
// ...
List<String> strings = Lists.newArrayList();
List<Integer> integers = Lists.newLinkedList();
There are overloads for varargs initialization and initialising from an Iterable<T>.
The advantage of these methods is that you don't need to specify the generic parameter explicitly as you would with the constructor - the compiler will infer it from the type of the variable.
More options to do the same thing with Java 8, not better, not worse, just different and if you want to do some extra work with the lists, Streams will provide you more alternatives (filter, map, reduce, etc.)
List<String> listA = Stream.of("a", "B", "C").collect(Collectors.toList());
List<Integer> listB = IntStream.range(10, 20).boxed().collect(Collectors.toList());
List<Double> listC = DoubleStream.generate(() -> { return new Random().nextDouble(); }).limit(10).boxed().collect(Collectors.toList());
LinkedList<Integer> listD = Stream.iterate(0, x -> x++).limit(10).collect(Collectors.toCollection(LinkedList::new));
As an option you can use double brace initialization here:
List<String> list = new ArrayList<String>(){
{
add("a");
add("b");
}
};
List<Object> nameOfList = new ArrayList<Object>();
You need to import List and ArrayList.
With Java 9, you are able to do the following to create an immutable List:
List<Integer> immutableList = List.of(1, 2, 3, 4, 5);
List<Integer> mutableList = new ArrayList<>(immutableList);
There are many ways to create a Set and a List. HashSet and ArrayList are just two examples. It is also fairly common to use generics with collections these days. I suggest you have a look at what they are
This is a good introduction for java's builtin collections. http://java.sun.com/javase/6/docs/technotes/guides/collections/overview.html
List arrList = new ArrayList();
Its better you use generics as suggested below:
List<String> arrList = new ArrayList<String>();
arrList.add("one");
Incase you use LinkedList.
List<String> lnkList = new LinkedList<String>();
List can be created in many ways:
1 - Constructor Initialization
List is an interface, and the instances of List can be created in the following ways:
List<Integer> list=new ArrayList<Integer>();
List<Integer> llist=new LinkedList<Integer>();
List<Integer> stack=new Stack<Integer>();
2- Using Arrays.asList()
List<Integer> list=Arrays.asList(1, 2, 3);
3- Using Collections class methods
Empty List
List<Integer> list = Collections.EMPTY_LIST;
OR
List<Integer> list = Collections.emptyList();
Collections.addAll(list = new ArrayList<Integer>(), 1, 2, 3, 4);
Unmodifiable List
List<Integer> list = Collections
.unmodifiableList(Arrays.asList(1, 2, 3));
Singleton List
List<Integer> list = Collections.singletonList(2);
You can find more way from the reference link below.
Reference:
https://www.geeksforgeeks.org/initializing-a-list-in-java/
Using Eclipse Collections you can create a List like this:
List<String> list1 = Lists.mutable.empty();
List<String> list2 = Lists.mutable.of("One", "Two", "Three");
If you want an immutable list:
ImmutableList<String> list3 = Lists.immutable.empty();
ImmutableList<String> list4 = Lists.immutable.of("One", "Two", "Three");
You can avoid auto-boxing by using primitive lists. Here's how you'd create int lists:
MutableIntList list5 = IntLists.mutable.empty();
MutableIntList list6 = IntLists.mutable.of(1, 2, 3);
ImmutableIntList list7 = IntLists.immutable.empty();
ImmutableIntList list8 = IntLists.immutable.of(1, 2, 3);
There are variants for all 8 primitives.
MutableLongList longList = LongLists.mutable.of(1L, 2L, 3L);
MutableCharList charList = CharLists.mutable.of('a', 'b', 'c');
MutableShortList shortList = ShortLists.mutable.of((short) 1, (short) 2, (short) 3);
MutableByteList byteList = ByteLists.mutable.of((byte) 1, (byte) 2, (byte) 3);
MutableBooleanList booleanList = BooleanLists.mutable.of(true, false);
MutableFloatList floatList = FloatLists.mutable.of(1.0f, 2.0f, 3.0f);
MutableDoubleList doubleList = DoubleLists.mutable.of(1.0, 2.0, 3.0);
Note: I am a committer for Eclipse Collections.
Try this:
List<String> messages = Arrays.asList("bla1", "bla2", "bla3");
Or:
List<String> list1 = Lists.mutable.empty(); // Empty
List<String> list2 = Lists.mutable.of("One", "Two", "Three");
If you need a serializable, immutable list with a single entity you can use:
List<String> singList = Collections.singletonList("stackoverlow");

Categories