I am running this code:
public class testttt {
public static void main(String[] args){
ArrayList<StringBuffer> listOne = new ArrayList <StringBuffer>();
listOne.add(new StringBuffer("One"));
listOne.add(new StringBuffer("Two"));
listOne.add(new StringBuffer("Three"));
ArrayList <StringBuffer> listTwo = new ArrayList <StringBuffer>(listOne);
listOne.add(new StringBuffer("Four"));
for (StringBuffer str : listTwo) {
str.append("2");
}
System.out.println("List One: " + listOne);
System.out.println("List Two: " + listTwo);
}
}
I thought by having the "new ArrayList" declaration when initializing listTwo I would have created a distinct array that would be independent from listOne. However, the output is:
List One: [One2, Two2, Three2, Four]
List Two: [One2, Two2, Three2]
I have a suspicion that the listTwo initialization only copied over the references from listOne, but I thought it would have been handled by the "new ArrayList" section.
Any explanation would be greatly appreciated!
By using the listOne for the listTwo construction, you are saying: "please create a new list, and then copy all elements from the first list into that second list".
And then of course, java is doing "call-by-value". This means: "copying" doesn't mean the creation of new StringBuffers. It means that both lists hold references to the same StringBuffer objects.
Thus when you iterate the second list, and modify members of the second list, you see the effects on the first list as well.
So, the "real" answer is: always understand the concepts you are using; the "real" message here isn't the explanation; but the fact that one core part of being a programmer is to be very precise about the code you write, and to really understand each and every tiny bit of statement your put in your code. Everything has a certain meaning; and if you don't know them, your code will keep "surprising" you.
You first create a List (listOne) that contains instances of StringBuffer.
Then you create another List (listTwo) that contains the same instances of StringBuffer. However, this is a different list.
Then you add to listOne one additional element. You change just listOne, not listTwo.
Then you change each StringBuffer instance within listTwo. Since listOne and listTwo contain, among others, the same instances of StringBuffer, this change is visible in listOne as well.
Note: you didn't put copies of the StringBuffer instances into listTwo, but references to the same objects!
Constructor and other methods perform shallow copy. As mentioned in this answer,
Shallow copies duplicate as little as possible. It tries to create a reference to same old object hence it creates a copy the collection structure, not the elements. With a shallow copy, two collections share the individual elements.
whereas a Deep copies everything and create duplicates. It copies all of the elements in the original collection duplicated.
You can use Collections utility class if you want to create a deep copy.
ArrayList <StringBuffer> listTwo = new ArrayList <StringBuffer>(listOne.size());
Collections.copy(listTwo , listOne);
When you use the copy constructor for ArrayList, you're telling the new list to copy the elements of the old list. What collections actually store in Java is references, and you get what's called a "shallow copy": copies of references, but the same shared objects.
When you then modify those objects, the changes are visible regardless of which list of references you use to get to them.
Related
I need to pass the same ArrayList from the main function to 3 different functions (all in different classes).
When the 1st function receives the ArrayList, it makes changes not only in the local copy of the list but also the original ArrayList in the main method gets modified. This indicates that the changes are being made at the memory address.
So, in the first function I copied the received arraylist into another arraylist of the same type, using:
for(int i=0;i<valuex.size();i++)
{
temp1=valuex.get(i);
VALUE.add(temp1);
}
This worked for the first time when I introduced this modification but then the same problem restored. Later I made three copies of the arraylist and passed each copy to each of the 3 functions. This too failed.
I didn't use
clone();
because this created the same problem some time back..
Please help...
You have described a shallow copy - you've made a fresh list, but you've got the same objects in each list.
If this isn't working for you, it suggests your method is modifying the list objects. To avoid this being a problem, you'll have to perform a deep copy - creating copies of each of your objects.
For example:
List<Foo> oldList = // ...
List<Foo> newList = new ArrayList<>();
for (Foo foo : oldList) {
Foo newFoo = new Foo(foo); // copy constructor
newList.add(newFoo);
}
When you passed a copy of the list to your three methods, you passed a reference to a copy of the list as a data structure. However, both lists, in memory, ended up pointing to the very same objects.
If your methods are changing the actual objects that the lists are pointing to, and you'd like to avoid that, then cloning the list is not enough: you must clone each and every object in the list as well.
By the way: the reason that clone() didn't work for you is that clone() only performs a shallow clone of the list: it creates a brand new ArrayList instance in memory, however the list's constituents are still the same objects (in memory) as the objects pointed-to by the original list.
You can just create a new ArrayList based on your existing arrayList before passing it in as argument.
List existingList = new ArrayList();
o1.m1(new ArrayList(existingList));
o2.m2(new ArrayList(existingList));
o3.m3(new ArrayList(existingList));
ArrayList contructor allows you to create a new ArrayList based on an existing collection.
http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#ArrayList(java.util.Collection)
I can addAll array elements in to ArrayList by following two ways,
First,
List<String> list1 = new ArrayList<String>();
list1.addAll(Arrays.asList("23,45,56,78".split(",")));
System.out.println(list1);
Second,
List<String> list2 = new ArrayList<String>();
list2.addAll(new ArrayList<String>(Arrays.asList("23,45,56,78".split(","))));
System.out.println(list2);
Both works fine. And my question is Is there any difference between these two. And which one can be used for better practice Why ?
Both approaches produce the same result, so in that respect they are equivalent.
The second one, however, is wasteful. Arrays.asList does not allocate additional memory - it just wraps a given array in a List-like API. Creating a new ArrayList, on the other hand, allocates, albeit temporarily, another array with the same size, and copies all the values from the source array to the internal array of the ArrayList's implementation.
With small arrays it's doubtful you'd even notice the difference, but the first approach is definitely more efficient.
The addAll method is defined on the Collection interface. With both examples, you are passing in a List. You aren't keeping the ArrayList you're creating in the second example, but it's not even necessary. Arrays.asList sends the List just fine into addAll by itself. The creation of the unnecessary ArrayList in the second example is unnecessary, so the first example is preferred.
Of the two you listed, the first is better. The second example creates another ArrayList object that isn't needed. Both would be functionally the same, but the first is more efficient.
As to the best practice, you can do this kind of thing in 1 line, not 2.
List<String> list2 = new ArrayList<String>(Arrays.asList("23,45,56,78".split(",")));
You can create a list by passing the arguments into it's constructor, a little cleaner than calling .addAll after creating the Object
I want that b1 and b2 to have their own sets of elements, then b1 and b2 should have its own elements in memory so that when b1/b2 is modified, others should not be affected.
buffer is an ArrayList containing many elements
List<Integer> b1 = new ArrayList<Integer>(buffer.size()) ;
List<Integer> b2 = new ArrayList<Integer>(buffer.size()) ) ;
Collections.copy(b1, buffer);
Collections.copy(b2, buffer);
I am getting this exception:
Exception in thread "main"
java.lang.IndexOutOfBoundsException: Source does not fit in dest
at java.util.Collections.copy(Collections.java:531)
at Trees.containsSumPrint(Trees.java:243)
at Trees.main(Trees.java:125)
The ArrayList(int) constructor gives a List that has size 0 it only ensures that n elements can be added before it needs to reallocate the underlying array.
A better way you can copy the lists is:
b1.addAll(buffer);
b2.addAll(buffer);
The semantics are the same as when you would have first added buffer.size() nulls to each array and called Collections.copy(b1,buffer);
If you want a deep copy (the elements also copied) you are going to have to handle each element separately
for(MyObject obj:buffer){
b1.add(obj.clone());
b2.add(obj.clone());
}
The Collections.copy(...) javadoc says this:
"Copies all of the elements from one list into another. After the operation, the index of each copied element in the destination list will be identical to its index in the source list. The destination list must be at least as long as the source list. If it is longer, the remaining elements in the destination list are unaffected.".
The ArrayList(int) constructor creates an empty list whose capacity (not size!) is given by the argument.
Since b1 is initially empty, copying a non-empty list to it (using copy) will fail, since the precondition (in bold) does not hold true (in general).
Basically, Collections.copy(...) is the wrong method to use.
What you should really be doing is this:
List<Integer> b1 = new ArrayList<Integer>(buffer.size());
List<Integer> b2 = new ArrayList<Integer>(buffer.size());
b1.addAll(buffer);
b2.addAll(buffer);
I'm assuming that you don't really want to create new instances of the list elements. If you do, I should point out that creating new instances of Integer objects is waste of time since Integer (like the other wrapper classes and String) is an immutable class.
You want a deep copy of each element. There is no standard way to achieve this, because deep copying could involve copying nested references to (collections of) other objects. The best way to do this is create a copy constructor, java.lang.Integer happens to have one! So I think you should do something like:
List<Integer> buffer = Arrays.asList(new Integer[] { 0, 1, 2, 3, 4 });
List<Integer> b1 = new ArrayList<Integer>();
List<Integer> b2 = new ArrayList<Integer>();
for (Integer element : buffer) {
b1.add(new Integer(element));
b2.add(new Integer(element));
}
This actually creates TWO copies, one in each target list. If one of the lists may contain the original elements just do:
for (Integer element : buffer) {
b1.add(new Integer(element));
b2.add(element);
}
Note that there also exists the cloneable interface. I advise against using this because it is easy to make mistakes with referred classes, collections and subclassing. A copy constructor is much easier to get right. See this page for some corroboration.
EDIT: on re-reading, maybe you don't want deep copies, in which case you can use the 'addAll' method as described by others. This will allow you to create multiple collections of the same object instances. You can then modify the contents/order of objects in one collection without affecting other collections. However if you modify an object instance, this will obviously be reflected by all other collections as well.
Also, StephenC rightfully points out that my above example is nutty. I agree, one would never 'deep copy' Integers like that normally, but it would makes sense for custom objects containing collections/references which I thought was the issue here.
What is the use of Collections.singletonList() in Java? I understand that it returns a list with one element. Why would I want to have a separate method to do that? How does immutability play a role here?
Are there any special useful use-cases for this method rather than just being a convenient method?
The javadoc says this:
"Returns an immutable list containing only the specified object. The returned list is serializable."
You ask:
Why would I want to have a separate method to do that?
Primarily as a convenience ... to save you having to write a sequence of statements to:
create an empty list object
add an element to it, and
wrap it with an immutable wrapper.
It may also be a bit faster and/or save a bit of memory, but it is unlikely that these small savings will be significant. (An application that creates vast numbers of singleton lists is unusual to say the least.)
How does immutability play a role here?
It is part of the specification of the method; see above.
Are there any special useful use-cases for this method, rather than just being a convenience method?
Clearly, there are use-cases where it is convenient to use the singletonList method. Indeed, any program where you need to use an immutable list with one element is a valid use-case. (It takes roughly zero imagination to think of one.)
But I don't know how you would (objectively) distinguish between an ordinary use-case and a "specially useful" one ...
From the javadoc
#param the sole object to be stored in the returned list.
#return an immutable list containing only the specified object.
example
import java.util.*;
public class HelloWorld {
public static void main(String args[]) {
// create an array of string objs
String initList[] = { "One", "Two", "Four", "One",};
// create one list
List list = new ArrayList(Arrays.asList(initList));
System.out.println("List value before: "+list);
// create singleton list
list = Collections.singletonList("OnlyOneElement");
list.add("five"); //throws UnsupportedOperationException
System.out.println("List value after: "+list);
}
}
Use it when code expects a read-only list, but you only want to pass one element in it. singletonList is (thread-)safe and fast.
Here's one view on the singleton methods:
I have found these various "singleton" methods to be useful for passing a single value to an API that requires a collection of that value. Of course, this works best when the code processing the passed-in value does not need to add to the collection.
To answer your immutable question:
Collections.singletonList will create an immutable List.
An immutable List (also referred to as an unmodifiable List) cannot have it's contents changed. The methods to add or remove items will throw exceptions if you try to alter the contents.
A singleton List contains only that item and cannot be altered.
If an Immutable/Singleton collections refers to the one which having only one object and which is not further gets modified, then the same functionality can be achieved by making a collection "UnmodifiableCollection" having only one object. Since the same functionality can be achieved by Unmodifiable Collection with one object, then what special purpose the Singleton Collection serves for?
singletonList can hold instance of any object. Object state can be modify.
List<Character> list = new ArrayList<Character>();
list.add('X');
list.add('Y');
System.out.println("Initial list: "+ list);
List<List<Character>> list2 = Collections.singletonList(list);
list.add('Z');
System.out.println(list);
System.out.println(list2);
We can not define unmodifiableList like above.
By looking at the code of Collections class, i got to know that when we are using the method unmodifiableList(List list) or unmodifiableCollection(Collection c) it is not creating a new object but it is returning the reference of the same object and overriding the methods which can modify the List [ add, addall, remove, retainAll ... ]
So i ran this test:
List modifiableList = new ArrayList();
modifiableList.add ( 1 );
List unmodifiableList = Collections.unmodifiableList( modifiableList );
// unmodifiableList.add(3); // it will throw the exception
modifiableList.add ( 2 );
System.out.println( unmodifiableList );
result is [ 1,2 ] .
Now the point is why it is referring to the same object? Why it don't create a new object?
(answer of the queston at the bottom)
When you create an unmodifiable list, the purpose is that it should not be modified by people other than you - i.e. clients of an API.
the method unmodifiableList(..) creates a new object of type UnmodifiableList (but this is not a public class), which gets the original list, and delegates all methods to it except the methods which would modify it.
The point is, as stated in the documentation:
Returns an unmodifiable view of the specified list. This method allows modules to provide users with "read-only" access to internal lists.
So, an example: You have a List of devices that your API has detected and can operate, and you want to give them a client of your API. But he is not supposed to change them. So you have two options:
give him a deep copy of your List, so that even if he modifies it, this does not change your list
give him an unmodifiable collection - he can't modify it, and you spare the creation of a new collection.
And now here comes the answer to the title of your question - the unmodifiable list is a view of the original collection. So if you need to add a new item to it - say, you have discovered a new device that was just plugged-in, the clients will be able to see it in their unmodifiable view.
Now the point is why it is referring
to the same object? Why it don't
create a new object?
Performance. It just doesn't scale to make a full copy. It would be a linear time operation to make a full copy which obviously isn't practical. Also, as others already noted, the point is that you can pass the reference of the unmodifiable list around without having to worry that it gets changed. This is very helpful for multithreaded programs.
From documentation:
public static List unmodifiableList(List list)
Returns an unmodifiable view of the specified list. This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.
The accepted Answer by Bozho is correct. Here's a bit more info, example code, and a suggested alternative.
The unmodifiableList Is Backed By Original List
That unmodifiableList method in Collections utility class does not create a new list, it creates a pseudo-list backed by the original list. Any add or remove attempts made through the "unmodifiable" object will be blocked, thus the name lives up to its purpose. But indeed, as you have shown, the original list can be modified and simultaneously affects our secondary not-quite-unmodifiable list.
This is spelled out in the class documentation:
Returns an unmodifiable view of the specified list. This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.
That fourth word is key: view. The new list object is not a fresh list. It is an overlay. Just like tracing paper or transparency film over a drawing stops you from making marks on the drawing, it does not stop you from going underneath to modify the original drawing.
Moral of the Story: Do not use Collections.unmodifiableList for making defensive copies of lists.
Ditto for Collections.unmodifiableMap, Collections.unmodifiableSet, and so on.
Here is another example demonstrating the issue.
String dog = "dog";
String cat = "cat";
String bird = "bird";
List< String > originalList = new ArrayList<>( 3 );
originalList.add( dog );
originalList.add( cat );
originalList.add( bird );
List< String > unmodList = Collections.unmodifiableList( originalList );
System.out.println( "unmod before: " + unmodList ); // Yields [dog, cat, bird]
originalList.remove( cat ); // Removing element from original list affects the unmodifiable list?
System.out.println( "unmod after: " + unmodList ); // Yields [dog, bird]
Google Guava
Instead of the Collections class, for defensive programming I recommend using the Google Guava library and its ImmutableCollections facility.
You can make a fresh list.
public static final ImmutableList<String> ANIMALS = ImmutableList.of(
dog,
cat,
bird );
Or you can make a defensive copy of an existing list. In this case you will get a fresh separate list. Deleting from the original list will not affect (shrink) the immutable list.
ImmutableList<String> ANIMALS = ImmutableList.copyOf( originalList ); // defensive copy!
But remember, while the collection’s own definition is separate, the contained objects are shared by both the original list and new immutable list. When making that defensive copy, we are not duplicating the "dog" object. Only one dog object remains in memory, both lists contain a reference pointing to the same dog. If the properties in the "dog" object are modified, both collections are pointing to that same single dog object and so both collections will see the dog’s fresh property value.
I Found one way to do this is
List unmodifiableList = Collections.unmodifiableList( new ArrayList(modifiableList));
List<String> strings = new ArrayList<String>();
// unmodifiable.add("New string");
strings.add("Aha 1");
strings.add("Aha 2");
List<String> unmodifiable = Collections.unmodifiableList(strings);
List<String> immutableList = Collections.unmodifiableList(new ArrayList<>(strings));
// Need some way to fix it so that Strings does not Modify
strings.add("Aha 3");
strings.add("Aha 4");
strings.remove(0);
for (String str : unmodifiable) {
System.out.println("Reference Modified :::" + str);
}
for (String str : immutableList) {
System.out.println("Reference Modified :::" + str);
}
I believe the secret lies in implementation details... Collection.unmodifiableList() will simply give you decorated modifiable list. I mean unmodifiable list contains reference to modifiable list internally.
you should go for creating new Object of a list, only when the original Object is going to be changed and you need a backup , when someone corrupts it , u can replace by new Object.
To create a ummodifiable object, i will wrap the original object and prevent add ,remove by throwing exception. but u know ,i can change each object present in the list .like if u have a person object in an umodifiable list , i can still change the name of the person object in the list.