How to copy Java Collections list - java

I have an ArrayList and I want to copy it exactly. I use utility classes when possible on the assumption that someone spent some time making it correct. So naturally, I end up with the Collections class which contains a copy method.
Suppose I have the following:
List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
List<String> b = new ArrayList<String>(a.size());
Collections.copy(b,a);
This fails because basically it thinks b isn't big enough to hold a. Yes I know b has size 0, but it should be big enough now shouldn't it? If I have to fill b first, then Collections.copy() becomes a completely useless function in my mind. So, except for programming a copy function (which I'm going to do now) is there a proper way to do this?

b has a capacity of 3, but a size of 0. The fact that ArrayList has some sort of buffer capacity is an implementation detail - it's not part of the List interface, so Collections.copy(List, List) doesn't use it. It would be ugly for it to special-case ArrayList.
As tddmonkey has indicated, using the ArrayList constructor which takes a collection is the way to in the example provided.
For more complicated scenarios (which may well include your real code), you may find the collections within Guava useful.

Calling
List<String> b = new ArrayList<String>(a);
creates a shallow copy of a within b. All elements will exist within b in the exact same order that they were within a (assuming it had an order).
Similarly, calling
// note: instantiating with a.size() gives `b` enough capacity to hold everything
List<String> b = new ArrayList<String>(a.size());
Collections.copy(b, a);
also creates a shallow copy of a within b. If the first parameter, b, does not have enough capacity (not size) to contain all of a's elements, then it will throw an IndexOutOfBoundsException. The expectation is that no allocations will be required by Collections.copy to work, and if any are, then it throws that exception. It's an optimization to require the copied collection to be preallocated (b), but I generally do not think that the feature is worth it due to the required checks given the constructor-based alternatives like the one shown above that have no weird side effects.
To create a deep copy, the List, via either mechanism, would have to have intricate knowledge of the underlying type. In the case of Strings, which are immutable in Java (and .NET for that matter), you don't even need a deep copy. In the case of MySpecialObject, you need to know how to make a deep copy of it and that is not a generic operation.
Note: The originally accepted answer was the top result for Collections.copy in Google, and it was flat out wrong as pointed out in the comments.

Just do:
List a = new ArrayList();
a.add("a");
a.add("b");
a.add("c");
List b = new ArrayList(a);
ArrayList has a constructor that will accept another Collection to copy the elements from

The answer by Stephen Katulka (accepted answer) is wrong (the second part).
It explains that Collections.copy(b, a); does a deep copy, which it does not. Both, new ArrayList(a); and Collections.copy(b, a); only do a shallow copy. The difference is, that the constructor allocates new memory, and copy(...) does not, which makes it suitable in cases where you can reuse arrays, as it has a performance advantage there.
The Java standard API tries to discourage the use of deep copies, as it would be bad if new coders would use this on a regular basis, which may also be one of the reason why clone() is not public by default.
The source code for Collections.copy(...) can be seen on line 552 at:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/Collections-Jar-Zip-Logging-regex/java/util/Collections.java.htm
If you need a deep copy, you have to iterate over the items manually, using a for loop and clone() on each object.

the simplest way to copy a List is to pass it to the constructor of the new list:
List<String> b = new ArrayList<>(a);
b will be a shallow copy of a
Looking at the source of Collections.copy(List,List) (I'd never seen it before) it seems to be for coping the elements index by index. using List.set(int,E) thus element 0 will over write element 0 in the target list etc etc. Not particularly clear from the javadocs I'd have to admit.
List<String> a = new ArrayList<>(a);
a.add("foo");
b.add("bar");
List<String> b = new ArrayList<>(a); // shallow copy 'a'
// the following will all hold
assert a.get(0) == b.get(0);
assert a.get(1) == b.get(1);
assert a.equals(b);
assert a != b; // 'a' is not the same object as 'b'

List b = new ArrayList(a.size())
doesn't set the size. It sets the initial capacity (being how many elements it can fit in before it needs to resize). A simpler way of copying in this case is:
List b = new ArrayList(a);

As hoijui mentions. The selected answer from Stephen Katulka contains a comment about Collections.copy that is incorrect. The author probably accepted it because the first line of code was doing the copy that he wanted. The additional call to Collections.copy just copies again. (Resulting in the copy happening twice).
Here is code to prove it.
public static void main(String[] args) {
List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
List<String> b = new ArrayList<String>(a);
System.out.println("There should be no output after this line.");
// Note, b is already a shallow copy of a;
for (int i = 0; i < a.size(); i++) {
if (a.get(i) != b.get(i)) {
System.out.println("Oops, this was a deep copy."); // Note this is never called.
}
}
// Now use Collections.copy and note that b is still just a shallow copy of a
Collections.copy(b, a);
for (int i = 0; i < a.size(); i++) {
if (a.get(i) != b.get(i)) {
System.out.println("Oops, i was wrong this was a deep copy"); // Note this is never called.
}
}
// Now do a deep copy - requires you to explicitly copy each element
for (int i = 0; i < a.size(); i++) {
b.set(i, new String(a.get(i)));
}
// Now see that the elements are different in each
for (int i = 0; i < a.size(); i++) {
if (a.get(i) == b.get(i)) {
System.out.println("oops, i was wrong, a shallow copy was done."); // note this is never called.
}
}
}

Most answers here do not realize the problem, the user wants to have a COPY of the elements from first list to the second list, destination list elements are new objects and not reference to the elements of original list.
(means changing an element of second list should not change values for corresponding element of source list.)
For the mutable objects we cannot use ArrayList(Collection) constructor because it will simple refer to the original list element and will not copy.
You need to have a list cloner for each object when copying.

Why dont you just use addAll method:
List a = new ArrayList();
a.add("1");
a.add("abc");
List b = b.addAll(listA);
//b will be 1, abc
even if you have existing items in b or you want to pend some elements after it, such as:
List a = new ArrayList();
a.add("1");
a.add("abc");
List b = new ArrayList();
b.add("x");
b.addAll(listA);
b.add("Y");
//b will be x, 1, abc, Y

Strings can be deep copied with
List<String> b = new ArrayList<String>(a);
because they are immutable. Every other Object not --> you need to iterate and do a copy by yourself.

If you want to copy an ArrayList, copy it by using:
List b = new ArrayList();
b.add("aa");
b.add("bb");
List a = new ArrayList(b);

private List<Item> cloneItemList(final List<Item> items)
{
Item[] itemArray = new Item[items.size()];
itemArray = items.toArray(itemArray);
return Arrays.asList(itemArray);
}

Every other Object not --> you need to iterate and do a copy by yourself.
To avoid this implement Cloneable.
public class User implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private String user;
private String password;
...
#Override
public Object clone() {
Object o = null;
try {
o = super.clone();
} catch(CloneNotSupportedException e) {
}
return o;
}
}
....
public static void main(String[] args) {
List<User> userList1 = new ArrayList<User>();
User user1 = new User();
user1.setUser("User1");
user1.setPassword("pass1");
...
User user2 = new User();
user2.setUser("User2");
user2.setPassword("pass2");
...
userList1 .add(user1);
userList1 .add(user2);
List<User> userList2 = new ArrayList<User>();
for(User u: userList1){
u.add((User)u.clone());
}
//With this you can avoid
/*
for(User u: userList1){
User tmp = new User();
tmp.setUser(u.getUser);
tmp.setPassword(u.getPassword);
...
u.add(tmp);
}
*/
}

The following output illustrates results of using copy constructor and Collections.copy():
Copy [1, 2, 3] to [1, 2, 3] using copy constructor.
Copy [1, 2, 3] to (smaller) [4, 5]
java.lang.IndexOutOfBoundsException: Source does not fit in dest
at java.util.Collections.copy(Collections.java:556)
at com.farenda.java.CollectionsCopy.copySourceToSmallerDest(CollectionsCopy.java:36)
at com.farenda.java.CollectionsCopy.main(CollectionsCopy.java:14)
Copy [1, 2] to (same size) [3, 4]
source: [1, 2]
destination: [1, 2]
Copy [1, 2] to (bigger) [3, 4, 5]
source: [1, 2]
destination: [1, 2, 5]
Copy [1, 2] to (unmodifiable) [4, 5]
java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableList.set(Collections.java:1311)
at java.util.Collections.copy(Collections.java:561)
at com.farenda.java.CollectionsCopy.copyToUnmodifiableDest(CollectionsCopy.java:68)
at com.farenda.java.CollectionsCopy.main(CollectionsCopy.java:20)
The source of full program is here: Java List copy. But the output is enough to see how java.util.Collections.copy() behaves.

And if you are using google guava, the one line solution would be
List<String> b = Lists.newArrayList(a);
This creates a mutable array list instance.

With Java 8 being null-safe, you could use the following code.
List<String> b = Optional.ofNullable(a)
.map(list -> (List<String>) new ArrayList<>(list))
.orElseGet(Collections::emptyList);
Or using a collector
List<String> b = Optional.ofNullable(a)
.map(List::stream)
.orElseGet(Stream::empty)
.collect(Collectors.toList())

Copy isn't useless if you imagine the use case to copy some values into an existing collection. I.e. you want to overwrite existing elements instead of inserting.
An example: a = [1,2,3,4,5] b = [2,2,2,2,3,3,3,3,3,4,4,4,] a.copy(b) = [1,2,3,4,5,3,3,3,3,4,4,4]
However I'd expect a copy method that would take additional parameters for the start index of the source and target collection, as well as a parameter for count.
See Java BUG 6350752

To understand why Collections.copy() throws an IndexOutOfBoundsException although you've made the backing array of the destination list large enough (via the size() call on the sourceList), see the answer by Abhay Yadav in this related question:
How to copy a java.util.List into another java.util.List

Related

Can individual array references be made final? [duplicate]

Is there an immutable alternative to the primitive arrays in Java? Making a primitive array final doesn't actually prevent one from doing something like
final int[] array = new int[] {0, 1, 2, 3};
array[0] = 42;
I want the elements of the array to be unchangeable.
Not with primitive arrays. You'll need to use a List or some other data structure:
List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));
My recommendation is to not use an array or an unmodifiableList but to use Guava's ImmutableList, which exists for this purpose.
ImmutableList<Integer> values = ImmutableList.of(0, 1, 2, 3);
As others have noted, you can't have immutable arrays in Java.
If you absolutely need a method that returns an array that doesn't influence the original array, then you'd need to clone the array each time:
public int[] getFooArray() {
return fooArray == null ? null : fooArray.clone();
}
Obviously this is rather expensive (as you'll create a full copy each time you call the getter), but if you can't change the interface (to use a List for example) and can't risk the client changing your internals, then it may be necessary.
This technique is called making a defensive copy.
There is one way to make an immutable array in Java:
final String[] IMMUTABLE = new String[0];
Arrays with 0 elements (obviously) cannot be mutated.
This can actually come in handy if you are using the List.toArray method to convert a List to an array. Since even an empty array takes up some memory, you can save that memory allocation by creating a constant empty array, and always passing it to the toArray method. That method will allocate a new array if the array you pass doesn't have enough space, but if it does (the list is empty), it will return the array you passed, allowing you to reuse that array any time you call toArray on an empty List.
final static String[] EMPTY_STRING_ARRAY = new String[0];
List<String> emptyList = new ArrayList<String>();
return emptyList.toArray(EMPTY_STRING_ARRAY); // returns EMPTY_STRING_ARRAY
As of Java 9 you can use List.of(...), JavaDoc.
This method returns an immutable List and is very efficient.
Another one answer
static class ImmutableArray<T> {
private final T[] array;
private ImmutableArray(T[] a){
array = Arrays.copyOf(a, a.length);
}
public static <T> ImmutableArray<T> from(T[] a){
return new ImmutableArray<T>(a);
}
public T get(int index){
return array[index];
}
}
{
final ImmutableArray<String> sample = ImmutableArray.from(new String[]{"a", "b", "c"});
}
Since Guava 22, from package com.google.common.primitives you can use three new classes, which have a lower memory footprint compared to ImmutableList.
ImmutableIntArray
ImmutableLongArray
ImmutableDoubleArray
They also have a builder. Example:
int size = 2;
ImmutableLongArray longArray = ImmutableLongArray.builder(size)
.add(1L)
.add(2L)
.build();
or, if the size is known at compile-time:
ImmutableLongArray longArray = ImmutableLongArray.of(1L, 2L);
This is another way of getting an immutable view of an array for Java primitives.
If you need (for performance reason or to save memory) native 'int' instead of 'java.lang.Integer', then you would probably need to write your own wrapper class. There are various IntArray implementations on the net, but none (I found) was immutable: Koders IntArray, Lucene IntArray. There are probably others.
The of(E... elements) method in Java9 can be used to create immutable list using just a line:
List<Integer> items = List.of(1,2,3,4,5);
The above method returns an immutable list containing an arbitrary number of elements. And adding any integer to this list would result in java.lang.UnsupportedOperationExceptionexception. This method also accepts a single array as an argument.
String[] array = ... ;
List<String[]> list = List.<String[]>of(array);
No, this is not possible. However, one could do something like this:
List<Integer> temp = new ArrayList<Integer>();
temp.add(Integer.valueOf(0));
temp.add(Integer.valueOf(2));
temp.add(Integer.valueOf(3));
temp.add(Integer.valueOf(4));
List<Integer> immutable = Collections.unmodifiableList(temp);
This requires using wrappers, and is a List, not an array, but is the closest you will get.
In some situations, it will be lighter weight to use this static method from Google Guava library: List<Integer> Ints.asList(int... backingArray)
Examples:
List<Integer> x1 = Ints.asList(0, 1, 2, 3)
List<Integer> x1 = Ints.asList(new int[] { 0, 1, 2, 3})
If you want to avoid both mutability and boxing, there is no way out of the box. But you can create a class which holds primitive array inside and provides read-only access to elements via method(s).
Implement java.util.function.IntUnaryOperator:
class ImmutableArray implements IntUnaryOperator {
private final int[] array;
ImmutableArray(int[] array) {
this.array = Arrays.copyOf(array, array.length);
}
#Override
public int applyAsInt(int index) {
return array[index];
}
}
Access the array: array[i] becomes immutableArray.applyAsInt(i).
I benchmarked primitive for loop retrieval with a modulus operation with 100_000_000 elements. The above PrimitiveArray took ~220ms; there was no significant difference with a primitive array. The same op on ArrayList took 480 ms, and the loading process took 21 seconds, depleted my heap space first try, and I had to increase this setting on the JVM. Loading of PrimitiveArray had taken 2 seconds.
iteration
if you want to iterate, implement Iterable and provide
public java.util.PrimitiveIterator.OfInt iterator() { return Arrays.stream(array).iterator(); }
This provides access to int nextInt method.
From PrimitiveIterator you also get method forEachRemaining(PrimitiveConsumer) which is helpful to replace an existing enhanced for loop.
Iterating manually with PrimitiveIterator.OfInt yielded performance of ~300ms.
While it's true that Collections.unmodifiableList() works, sometimes you may have a large library having methods already defined to return arrays (e.g. String[]).
To prevent breaking them, you can actually define auxiliary arrays that will store the values:
public class Test {
private final String[] original;
private final String[] auxiliary;
/** constructor */
public Test(String[] _values) {
original = new String[_values.length];
// Pre-allocated array.
auxiliary = new String[_values.length];
System.arraycopy(_values, 0, original, 0, _values.length);
}
/** Get array values. */
public String[] getValues() {
// No need to call clone() - we pre-allocated auxiliary.
System.arraycopy(original, 0, auxiliary, 0, original.length);
return auxiliary;
}
}
To test:
Test test = new Test(new String[]{"a", "b", "C"});
System.out.println(Arrays.asList(test.getValues()));
String[] values = test.getValues();
values[0] = "foobar";
// At this point, "foobar" exist in "auxiliary" but since we are
// copying "original" to "auxiliary" for each call, the next line
// will print the original values "a", "b", "c".
System.out.println(Arrays.asList(test.getValues()));
Not perfect, but at least you have "pseudo immutable arrays" (from the class perspective) and this will not break related code.
Well.. arrays are useful to pass as constants (if they were) as variants parameters.

Constructing a List<T> from an Enum

What it comes down to is I'm attempting to construct a List<T> from the java.util.List package based on an enumerator, but here's the catch- I don't want the first value to be in the list. The way that I've come up with doing this... Well... It can't be a good thing.
Here's the code I'm using:
Arrays.asList(Arrays.asList(MyEnum.values()).remove(0));
This effectively creates a List<> from my enum, and removes the first value, then tries to create another list with the created list.
This may actually be the correct way to do it, but just looking at it is screaming "Inefficient". I showed it to a few people on a forum that I'm a member of and they all said how ugly it was, and laughed; However not a single one of them could/would provide a better way to go about doing it.
I don't think that code is really ugly or inefficient. The bigger problem is it doesn't work because the list returned by Arrays.asList is backed by the underlying array, and so it has a fixed size.
You can use subList instead of remove to get it working:
List<MyEnum> list = Arrays.asList(MyEnum.values());
list = list.subList(1, list.size());
This means that the resulting list actually consists of two list objects (the asList and its subList), which may or may not bother you. However, you can create a flat ArrayList from the resulting list:
list = new ArrayList<>(list);
If you'd rather minimize object allocation, loop the values and add them to a single list directly:
MyEnum[] values = MyEnum.values();
List<MyEnum> list = new ArrayList<>(values.length - 1);
for (int i = 1; i < values.length; i++)
list.add(values[i]);
How about:
Arrays.asList(MyEnum.values()).subList(1, MyEnum.values().length);
Are you sure you can't (wouldn't want to) use MyEnum.values and treat your first element differently where it's used?
public enum Enums {
first,
b,
c,
d,
e,
f;
public boolean isFirst(Enums e) {
return e == first;
}
}
This would work:
List<T> enums = Arrays.asList(Arrays.copyOfRange(MyEnum.values(), 1, MyEnum.values().length - 1));
Or java 8:
Arrays.stream(MyEnum.values()).collect(Collectors.toList()).subList(1, MyEnum.values() - 1);
Hmmm... not much better .

Add arraylist to 2d arraylist

I am having a list in the format
ArrayList<Integer> list = new ArrayList();
where I add and remove various elements in a loop. However, I need some structure where I can store the temporary lists so that I can access them later.
So for example, if I do System.out.print(list) it will return
[1,2,3,4]
then I need to call something like store.add(list)
and then if I add another element to the list - list.add(5) it becomes
[1,2,3,4,5]
then again
store.add(list)
and by calling System.out.print(store) it should return
[1,2,3,4]
[1,2,3,4,5]
In other words, store should be something like list within list?
List in list creating like this: List<List<Integer>> listInList = new ArrayList<List<Integer>>();
I suppose you want to have multiple versions of the same list.
You can't get that by just having a List of List.
The list will store only reference to the member lists stored inside it. So when you edit your list, all older versions will be edited as well. It's the same list behind the scene.
The correct way to use the List<List<Integer>> would be as follows.
List<List<Integer>> store = new ArrayList<>(); // Create storage for versions
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
store.add(new ArrayList<>(list)); // Add list's copy to store.
list.add(5); // Edit it as you want.
store.add(new ArrayList<>(list)); // Add list's copy to store.
System.out.println(store); // Print all versions
Output:
[[1, 2, 3, 4], [1, 2, 3, 4, 5]]
Hope this helps.
It is somewhat wasteful to store every new list, especially when the changes to the previous are very simple (e.g. additions and deletions at/from the end). You could come up with a strategy of keeping track of changes rather than storing the same information repeatedly.
First, you should decide which of the following is more important:
Have the list of lists readily available, at the expense of memory. This is desirable when you know you will need it very often and therefore cannot afford the overhead of generating it on-the-fly from history.
Use space efficiently, at the occasional cost of computing the list of lists from history. This is desirable when you make many changes and use the list of lists rarely.
The solutions already posted address 1., so here is a proposal for 2. (I will restrict the possible operations to adding and removing from the rear for the sake of brevity):
public enum Operation { ADD, REMOVE }
public class Modification {
Operation operation;
Integer element;
public Modification(Operation operation, Integer element) {
this.operation = operation; // could add some sanity checks (e.g. cannot remove from empty list)
this.element = element;
}
}
List<Integer> initialList = Arrays.asList(1, 2, 3, 4);
List<Modification> history = new ArrayList<>();
history.add(new Modification(Operation.ADD, 5));
Then you can define a function to compute the list of lists that you need:
List<List<Integer>> getAllLists (List<Integer> initialList, List<Modification> history) {
List<List<Integer>> allLists = new ArrayList<>();
allLists.add(initialList);
prevList = initialList;
for (Modification modification : history) {
prevList = new ArrayList<>(prevList);
if (modification.operation == ADD) prevList.add(modification.element);
else prevList.remove(prevList.size()-1);
allLists.add(prevList);
}
return allLists;
}

Difference between Arrays.asList(array) and new ArrayList<Integer>(Arrays.asList(array))

What is the difference between
List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia)); // Copy
List<Integer> list2 = Arrays.asList(ia);
, where ia is an array of integers?
I came to know that some operations are not allowed in list2. Why is it so?
How is it stored in memory (references / copy)?
When I shuffle the lists, list1 doesn't affect the original array, but list2 does. But still list2 is somewhat confusing.
How does ArrayList being upcasted to list differ from creating a new ArrayList?
list1 differs from (1)
ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));
First, let's see what this does:
Arrays.asList(ia)
It takes an array ia and creates a wrapper that implements List<Integer>, which makes the original array available as a list. Nothing is copied and all, only a single wrapper object is created. Operations on the list wrapper are propagated to the original array. This means that if you shuffle the list wrapper, the original array is shuffled as well, if you overwrite an element, it gets overwritten in the original array, etc. Of course, some List operations aren't allowed on the wrapper, like adding or removing elements from the list, you can only read or overwrite the elements.
Note that the list wrapper doesn't extend ArrayList - it's a different kind of object. ArrayLists have their own, internal array, in which they store their elements, and are able to resize the internal arrays etc. The wrapper doesn't have its own internal array, it only propagates operations to the array given to it.
On the other hand, if you subsequently create a new array as
new ArrayList<Integer>(Arrays.asList(ia))
then you create new ArrayList, which is a full, independent copy of the original one. Although here you create the wrapper using Arrays.asList as well, it is used only during the construction of the new ArrayList and is garbage-collected afterwards. The structure of this new ArrayList is completely independent of the original array. It contains the same elements (both the original array and this new ArrayList reference the same integers in memory), but it creates a new, internal array, that holds the references. So when you shuffle it, add, remove elements etc., the original array is unchanged.
Well, this is because ArrayList resulting from Arrays.asList() is not of the type java.util.ArrayList.
Arrays.asList() creates an ArrayList of type java.util.Arrays$ArrayList which does not extend java.util.ArrayList, but only extends java.util.AbstractList.
List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia)); //copy
In this case, list1 is of type ArrayList.
List<Integer> list2 = Arrays.asList(ia);
Here, the list is returned as a List view, meaning it has only the methods attached to that interface. Hence why some methods are not allowed on list2.
ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));
Here, you are creating a new ArrayList. You're simply passing it a value in the constructor. This is not an example of casting. In casting, it might look more like this:
ArrayList list1 = (ArrayList)Arrays.asList(ia);
First of all, the Arrays class is a utility class which contains a number of utility methods to operate on Arrays (thanks to the Arrays class. Otherwise, we would have needed to create our own methods to act on Array objects)
asList() method:
asList method is one of the utility methods of Array class, it is a static method that's why we can call this method by its class name (like Arrays.asList(T...a) )
Now here is the twist. Please note that this method doesn't create new ArrayList object. It just returns a List reference to an existing Array object (so now after using asList method, two references to existing Array object gets created)
and this is the reason. All methods that operate on List object, may not work on this Array object using the List reference. Like
for example, Arrays size is fixed in length, hence you obviously can not add or remove elements from Array object using this List reference (like list.add(10) or list.remove(10);. Else it will throw UnsupportedOperationException).
any change you are doing using a list reference will be reflected in the exiting Arrays object (as you are operating on an existing Array object by using a list reference)
In the first case, you are creating a new Arraylist object (in the second case, only a reference to existing Array object is created, but not a new ArrayList object), so now there are two different objects. One is the Array object and another is the ArrayList object and there isn't any connection between them (so changes in one object will not be reflected/affected in another object (that is, in case 2, Array and Arraylist are two different objects)
Case 1:
Integer [] ia = {1,2,3,4};
System.out.println("Array : "+Arrays.toString(ia));
List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia)); // new ArrayList object is created , no connection between existing Array Object
list1.add(5);
list1.add(6);
list1.remove(0);
list1.remove(0);
System.out.println("list1: " + list1);
System.out.println("Array: " + Arrays.toString(ia));
Case 2:
Integer [] ia = {1,2,3,4};
System.out.println("Array: " + Arrays.toString(ia));
List<Integer> list2 = Arrays.asList(ia); // Creates only a (new) List reference to the existing Array object (and NOT a new ArrayList Object)
// list2.add(5); // It will throw java.lang.UnsupportedOperationException - invalid operation (as Array size is fixed)
list2.set(0,10); // Making changes in the existing Array object using the List reference - valid
list2.set(1,11);
ia[2]=12; // Making changes in the existing Array object using the Array reference - valid
System.out.println("list2: " + list2);
System.out.println("Array: " + Arrays.toString(ia));
An explanation with documentation references would be better for someone looking for answer.
1. java.util.Arrays
This is a utility class with bunch of static methods to operate on given array
asList is one such static method that takes input array and returns an object of java.util.Arrays.ArrayList which is a static nested class that extends AbstractList<E> which in turn implements List interface.
So Arrays.asList(inarray) returns a List wrapper around the input array, but this wrapper is java.util.Arrays.ArrayList and not java.util.ArrayList and it refers to the same array, so adding more elements to the List wrapped array would affect the original one too and also we cannot change the length.
2. java.util.ArrayList
ArrayList has a bunch of overloaded constructors
public ArrayList() - // Returns arraylist with default capacity 10
public ArrayList(Collection<? extends E> c)
public ArrayList(int initialCapacity)
So when we pass the Arrays.asList returned object, i.e., List(AbstractList) to the second constructor above, it will create a new dynamic array (this array size increases as we add more elements than its capacity and also the new elements will not affect the original array) shallow copying the original array (shallow copy means it copies over the references only and does not create a new set of same objects as in original array)
String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> namesList = Arrays.asList(names);
or
String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> temp = Arrays.asList(names);
The above statement adds the wrapper on the input array. So the methods like add and remove will not be applicable on the list reference object 'namesList'.
If you try to add an element in the existing array/list then you will get "Exception in thread "main" java.lang.UnsupportedOperationException".
The above operation is readonly or viewonly.
We can not perform add or remove operation in list object.
But
String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.ArrayList<String> list1 = new ArrayList<>(Arrays.asList(names));
or
String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> listObject = Arrays.asList(names);
java.util.ArrayList<String> list1 = new ArrayList<>(listObject);
In the above statement you have created a concrete instance of an ArrayList class and passed a list as a parameter.
In this case, methods add and remove will work properly as both methods are from ArrayList class, so here we won't get any UnSupportedOperationException.
Changes made in the Arraylist object (method add or remove an element in/from an arraylist) will get not reflect in to the original java.util.List object.
String names[] = new String[] {
"Avinash",
"Amol",
"John",
"Peter"
};
java.util.List < String > listObject = Arrays.asList(names);
java.util.ArrayList < String > list1 = new ArrayList < > (listObject);
for (String string: list1) {
System.out.print(" " + string);
}
list1.add("Alex"); // Added without any exception
list1.remove("Avinash"); // Added without any exception will not make any changes in original list in this case temp object.
for (String string: list1) {
System.out.print(" " + string);
}
String existingNames[] = new String[] {
"Avinash",
"Amol",
"John",
"Peter"
};
java.util.List < String > namesList = Arrays.asList(names);
namesList.add("Bob"); // UnsupportedOperationException occur
namesList.remove("Avinash"); // UnsupportedOperationException
Note that, in Java 8, 'ia' above must be Integer[] and not int[]. Arrays.asList() of an int array returns a list with a single element. When using the OP's code snippet, the compiler will catch the issue, but some methods (e.g., Collections.shuffle()) will silently fail to do what you expect.
Many people have answered the mechanical details already, but it's worth noting:
This is a poor design choice, by Java.
Java's asList method is documented as "Returns a fixed-size list...". If you take its result and call (say) the .add method, it throws an UnsupportedOperationException. This is unintuitive behavior! If a method says it returns a List, the standard expectation is that it returns an object which supports the methods of interface List. A developer shouldn't have to memorize which of the umpteen util.List methods create Lists that don't actually support all the List methods.
If they had named the method asImmutableList, it would make sense. Or if they just had the method return an actual List (and copy the backing array), it would make sense. They decided to favor both runtime-performance and short names, at the expense of violating both the principle of least astonishment and the good object-oriented practice of avoiding UnsupportedOperationExceptions.
(Also, the designers might have made a interface ImmutableList, to avoid a plethora of UnsupportedOperationExceptions.)
package com.copy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class CopyArray {
public static void main(String[] args) {
List<Integer> list1, list2 = null;
Integer[] intarr = { 3, 4, 2, 1 };
list1 = new ArrayList<Integer>(Arrays.asList(intarr));
list1.add(30);
list2 = Arrays.asList(intarr);
// list2.add(40); Here, we can't modify the existing list,because it's a wrapper
System.out.println("List1");
Iterator<Integer> itr1 = list1.iterator();
while (itr1.hasNext()) {
System.out.println(itr1.next());
}
System.out.println("List2");
Iterator<Integer> itr2 = list2.iterator();
while (itr2.hasNext()) {
System.out.println(itr2.next());
}
}
}
Arrays.asList()
This method returns its own implementation of List. It takes an array as an argument and builds methods and attributes on top of it, since it is not copying any data from an array but using the original array this causes alteration in original array when you modify list returned by the Arrays.asList() method.
On the other hand, ArrayList(Arrays.asList());
is a constructor of ArrayList class which takes a list as argument and returns an ArrayList that is independent of list, i.e., Arrays.asList() in this case passed as an argument.
That is why you see these results.
1.List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia)); //copy
2.List<Integer> list2 = Arrays.asList(ia);
In line 2, Arrays.asList(ia) returns a List reference of inner class object defined within Arrays, which is also called ArrayList but is private and only extends AbstractList. This means what returned from Arrays.asList(ia) is a class object different from what you get from new ArrayList<Integer>.
You cannot use some operations to line 2 because the inner private class within Arrays does not provide those methods.
Take a look at this link and see what you can do with the private inner class:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/Arrays.java#Arrays.ArrayList
Line 1 creates a new ArrayList object copying elements from what you get from line 2. So you can do whatever you want since java.util.ArrayList provides all those methods.
In response to some comments asking questions about the behaviour of Arrays.asList() since Java 8:
int[] arr1 = {1,2,3};
/*
Arrays are objects in Java, internally int[] will be represented by
an Integer Array object which when printed on console shall output
a pattern such as
[I#address for 1-dim int array,
[[I#address for 2-dim int array,
[[F#address for 2-dim float array etc.
*/
System.out.println(Arrays.asList(arr1));
/*
The line below results in Compile time error as Arrays.asList(int[] array)
returns List<int[]>. The returned list contains only one element
and that is the int[] {1,2,3}
*/
// List<Integer> list1 = Arrays.asList(arr1);
/*
Arrays.asList(arr1) is Arrays$ArrayList object whose only element is int[] array
so the line below prints [[I#...], where [I#... is the array object.
*/
System.out.println(Arrays.asList(arr1));
/*
This prints [I#..., the actual array object stored as single element
in the Arrays$ArrayList object.
*/
System.out.println(Arrays.asList(arr1).get(0));
// prints the contents of array [1,2,3]
System.out.println(Arrays.toString(Arrays.asList(arr1).get(0)));
Integer[] arr2 = {1,2,3};
/*
Arrays.asList(arr) is Arrays$ArrayList object which is
a wrapper list object containing three elements 1,2,3.
Technically, it is pointing to the original Integer[] array
*/
List<Integer> list2 = Arrays.asList(arr2);
// prints the contents of list [1,2,3]
System.out.println(list2);
Summary of the difference -
When a list is created without using the new, the operator Arrays.asList() method returns a wrapper which means:
you can perform an add/update operation.
the changes done in the original array will be reflected to List as well and vice versa.

Testing implementation of '<T>' List

I have written my own implementation of java.utils.List. Now I'd like to test it, but I cannot manage to fill my collection with objects since it shows <identifier> expected whenever I add anything :
public static void main(String[] args) {}
MyCollection col = new MyCollection(10);
int[] tab = {1,2,4,5,6};
col.add(tab);
And the whole code here :
http://paste.pocoo.org/show/291343/
EDIT
MyCollection<Integer> col = new MyCollection<Integer>(10);
Integer[] tab = {1,2,4,5,6};
col.add(tab);
still the same :/
You're trying to add an int[] as item of a Collection<Integer> which accepts Integer (or autoboxed int) items only. This would only work if you have a Collection<int[]> (of which the added array would then be the sole item).
To convert an int[] to a Collection<Integer>, you need to loop over it:
int[] array = { 1, 2, 3, 4, 5 };
Collection<Integer> collection = new ArrayList<Integer>();
for (int item : array) {
collection.add(item);
}
See also:
Arrays tutorial
Collections tutorial
Generics tutorial
You're missing your Type. It's a generic class, so it should be something like
MyCollection<Integer> col = new MyCollection<Integer>(10);
Change:
MyCollection<Integer> col = new MyCollection<Interger>(10);
You need to specify the T of your MyCollection.
The generic implications here would not cause an error, you would simply get a warning because any object you add to the list is erased to Object, so you could add any object and would lose type safety.
You have instantiated a list whose members are a single object, whatever the type may be, but you're trying to add an array as a single member. You have a couple of options, but I would stick with:
List<Integer> myCollection = new MyCollection<Integer>(10);
myCollection.addAll(Arrays.asList(1, 2, 3, 4, 5, 6));
If you really intended on have a list of arrays, you would do:
List<Integer[]> myCollection = new MyCollection<Integer[]>(10);
myCollection.add(new Integer[]{1,2,3,4,5,6});
A couple of notes:
Program to the interface (see my example)
Your implementation is called MyCollection, but it's actually an implementation of List, so a name like MyList seems more appropriate unless you plan on actually extending Collection.
I assume this is just an exercise, but I don't see the point in extending List. You know that java.util.ArrayList exists right?

Categories