How do I clone a generic List in Java? - java

I have an ArrayList<String> that I'd like to return a copy of. ArrayList has a clone method which has the following signature:
public Object clone()
After I call this method, how do I cast the returned Object back to ArrayList<String>?

Why would you want to clone? Creating a new list usually makes more sense.
List<String> strs;
...
List<String> newStrs = new ArrayList<>(strs);
Job done.

ArrayList newArrayList = (ArrayList) oldArrayList.clone();

This is the code I use for that:
ArrayList copy = new ArrayList (original.size());
Collections.copy(copy, original);
Hope is usefull for you

With Java 8 it can be cloned with a stream.
import static java.util.stream.Collectors.toList;
...
List<AnObject> clone = myList.stream().collect(toList());

Be advised that Object.clone() has some major problems, and its use is discouraged in most cases. Please see Item 11, from "Effective Java" by Joshua Bloch for a complete answer. I believe you can safely use Object.clone() on primitive type arrays, but apart from that you need to be judicious about properly using and overriding clone. You are probably better off defining a copy constructor or a static factory method that explicitly clones the object according to your semantics.

I think this should do the trick using the Collections API:
Note: the copy method runs in linear time.
//assume oldList exists and has data in it.
List<String> newList = new ArrayList<String>();
Collections.copy(newList, oldList);

I find using addAll works fine.
ArrayList<String> copy = new ArrayList<String>();
copy.addAll(original);
parentheses are used rather than the generics syntax

List<String> shallowClonedList = new ArrayList<>(listOfStrings);
Keep in mind that this is only a shallow not a deep copy, ie. you get a new list, but the entries are the same. This is no problem for simply strings. Get's more tricky when the list entries are objects themself.

If you want this in order to be able to return the List in a getter it would be better to do:
ImmutableList.copyOf(list);

To clone a generic interface like java.util.List you will just need to cast it. here you are an example:
List list = new ArrayList();
List list2 = ((List) ( (ArrayList) list).clone());
It is a bit tricky, but it works, if you are limited to return a List interface, so anyone after you can implement your list whenever he wants.
I know this answer is close to the final answer, but my answer answers how to do all of that while you are working with List -the generic parent- not ArrayList

Be very careful when cloning ArrayLists. Cloning in java is shallow. This means that it will only clone the Arraylist itself and not its members. So if you have an ArrayList X1 and clone it into X2 any change in X2 will also manifest in X1 and vice-versa. When you clone you will only generate a new ArrayList with pointers to the same elements in the original.

This should also work:
ArrayList<String> orig = new ArrayList<String>();
ArrayList<String> copy = (ArrayList<String>) orig.clone()

ArrayList first = new ArrayList ();
ArrayList copy = (ArrayList) first.clone ();

I am not a java professional, but I have the same problem and I tried to solve by this method. (It suppose that T has a copy constructor).
public static <T extends Object> List<T> clone(List<T> list) {
try {
List<T> c = list.getClass().newInstance();
for(T t: list) {
T copy = (T) t.getClass().getDeclaredConstructor(t.getclass()).newInstance(t);
c.add(copy);
}
return c;
} catch(Exception e) {
throw new RuntimeException("List cloning unsupported",e);
}
}

Related

Java - Add one element to an immutable list

I need an immutable list where I can get derive a second immutable list preserving all elements of the previous list plus an additional element in Java (without additional libraries).
Note: This question is similar to What is an efficient and elegant way to add a single element to an immutable set? but I need a list and don't have Guava.
What I have tried so far:
var list = List.of(someArrayOfInitialElements);
var newList = Stream.concat(list.stream(), Stream.of(elementToAppend))
.collect(CollectorsCollectors.toUnmodifiableList());
That would work but creating a stream and copying elements one by one seems inefficient to me. You could basically bulk copy memory given that List.of() stores data in a field-based or array-based data structure.
Is there a more efficient solution than using streams? A better data structure in the Java standard library that I am missing?
I would create a new ArrayList append the element and then return that as an unmodifiable list. Something like,
private static <T> List<T> appendOne(List<T> al, T t) {
List<T> bl = new ArrayList<>(al);
bl.add(t);
return Collections.unmodifiableList(bl);
}
And to test it
public static void main(String[] args) {
List<String> al = appendOne(new ArrayList<>(), "1");
List<String> bl = appendOne(al, "2");
System.out.println(bl);
}
I get (unsurprisingly):
[1, 2]
See this code run at IdeOne.com.
The Answer by Frisch is correct, and should be accepted. One further noteā€¦
Calling Collections.unmodifiableList produces a collection that is a view onto the original mutable list. So a modification to the original list will "bleed through" to the not-so-immutable second list.
This issue does not apply to the correct code shown in that Answer, because the new ArrayList object deliberately goes out-of-scope. Therefore that new list cannot be accessed for modification. But in other coding scenarios, this issue could be a concern.
List.copyOf
If you want an independent and truly immutable second list, use List.copyOf in Java 10+. This returns an unmodifiable list.
return List.copyOf( bl ) ;
Both answers are great, I would create a bit more generic solution:
private static <T> List<T> append(final List<T> al, final T... ts) {
final List<T> bl = new ArrayList<>(al);
for (final T t : ts) {
bl.add(t);
}
return List.copyOf(bl);
}
It can be used exactly like previous answer:
List<String> al = append(new ArrayList<>(), "1");
List<String> bl = append(al, "2");
System.out.println(bl);
But also slightly more efficient:
List<String> bl = append(new ArrayList<>(), "1", "2");
System.out.println(bl);

Assigning List with preserving reference

Suppose I have two Lists and I want to copy/assign all of one list to another list with preserving reference to the original list. I use this code
List<String> mylist = new List<String>();
List<String> another = getSomeList();
// I have to do
mylist.clear();
mylist.addAll(another);
This works fine, but my question is, is there any better way to do this?
Thanks
I don't think that there is an easier way. You can just implement your own list that has e.g. a setAll() method.
class MyArrayList<E> extends ArrayList<E> {
public void setAll(Collection<E> collection) {
clear();
addAll(collection);
}
}
But this only moves the the clear() and addAll() invokation into another method. Sure from a clients prespective it makes the call easier
MyArrayList<String> mylist = new MyArrayList<String>();
mylist.setAll(another);
but at the price that you use a special list implementation. Maybe you only use this implementation inside of a class and your api does not expose that you use a MyArrayList. Than it might be ok. I would just do it the way you already do.
is there any better way to do this?
No, not for your specifications. You can delete mylist = another;.
And there's no need to call mylist.clear() when you just assigned mylist = new List<String>();
So really all you need is that last line where you addAll(another).
You can loop through first and add all elements into another:
for(String s : mylist){
another.add(s);
}

What is the best way to convert a raw vector to type safe list(Arraylist)

I have a function that return a raw vector. I know that all the elements in the vector are string but the code stays for leagacy reasons. I want to get a arraylist from this data.
One naive way is to iterate the vector and add elements to the list. Is there any short way of doing it which can prevent looping. Or may be a direct function which enables this.
Edit:
Example:
Vector f1() {} //f1 returns raw vector
I want to achieve the following:
List<String> l = new ArrayList<String>();
Vector vec = f1();
for(Object obj: vec) {
l.add((String) obj);
}
Note: I have not checked if the above code compiles. Please treat it as a pseudo code
If you are 100% sure the Vector only contains Strings, the simplest way is:
List<String> list = new ArrayList<>(vector);
Note that this will compile and run fine, even if you Vector contains other types of objects. However this:
list.get(i);
will throw a ClassCastException if the i-th element was not a String.
Since you have a raw Vector you will get warnings. If you want to get rid of them you can use:
#SuppressWarnings(value = {"unchecked", "rawtypes"})
public static List<String> rawVectorToList(Vector v) {
return new ArrayList<>(v);
}
An alternative to detect casting issues fast is to copy the array manually (what the copy constructor does under the hood):
Vector v = ...;
String[] elements = Arrays.copyOf(v.toArray(), v.size(), String[].class);
List<String> list = Arrays.asList(elements);
or if you need the list to be mutable:
List<String> list = new ArrayList<> (Arrays.asList(elements));
This has the benefit of checking the type at copy time.

Passing ArrayList as value only and not reference

Simply put, I have a method with an ArrayList parameter. In the method I modify the contents of the ArrayList for purposes relevant only to what is returned by the method. Therefore, I do not want the ArrayList which is being passed as the parameter to be affected at all (i.e. not passed as a reference).
Everything I have tried has failed to achieve the desired effect. What do I need to do so that I can make use of a copy of the ArrayList within the method only, but not have it change the actual variable?
Even if you had a way to pass the array list as a copy and not by reference it would have been only a shallow copy.
I would do something like:
void foo(final ArrayList list) {
ArrayList listCopy = new ArrayList(list);
// Rest of the code
}
And just work on the copied list.
You can create a copy of the ArrayList using ArrayList's copy constructor:
ArrayList copy = new ArrayList(original);
But if the elements of the list are also objects, then you must be aware that modifying a member of the copy will also modify that member in the original.
You could pass Collections#unmodifiableList(yourList) in order to send an unmodifiable copy of your list. By the way, your List<Whatever> is passed by value since Java always pass by value, note that in foo(List<Whatever> list) method you can not modify the list value but you can modify its contents.
public class MyClass {
List<Whatever> list = new ArrayList<Whatever>();
public void bar() {
//filling list...
foo(Collections.unmodifiableList(list));
}
public void foo(List<Whatever> list) {
//do what you want with list except modifying it...
}
}
You could use the .clone method or a CopyOnWriteArrayList to make a copy, thereby not impacting the original.
Try this in you method :
void method(List<Integer> list) {
List copyList = new ArrayList<Integer>();
copyList.addAll(list); // This will create a copy of all the emlements of your original list
}
I'm not sure on why, even after new ArrayList<MyObj>(old) the object was still changing reference in places it wasn't supposed to. So I had to instantiate a new copy of the objects inside.
I made a copy constructor like the one on the ArrayList and did like
newArray = new ArrayList<MyObj>();
for (int i = 0; i < oldArray.size(); i++) {
newArray.add(new MyObj(ondArray.get(i)));
}
Just hope to help someone else if the answer from Avi is not enough in your case, like mine with a code too messy to even understand =P
Just clone it.
public ArrayList cloneArrayList(ArrayList lst){
ArrayList list = new ArrayList();
for (int i=0; i<lst.size(); i++){
list.add(lst.get(i));
}
return list;
}
Add suggested in the comments, you can also use
ArrayList copy = new ArrayList(original);
and also
ArrayList copy = new ArrayList();
copy.addAll(original);
On the lines of the existing answers but using the ArrayList API. You can use subList(fromIndex, toIndex) method. It explicitly creates a view of the list with only desired elements (of course, in sequence). Here, even if you modify the view with add/remove etc operations, it won't change the original list. It saves you from explicitly creating a copy.
Something like this:
public void recursiveMethod(List<Integer> list) {
if(base)
return;
recursiveCall(list);
// following will just create a tail list but will not actually modify the list
recursiveCall(list.subList(1, list.size());
}

Setting a list equal to list using equal sign or copy constructor?

This is a simple question but if I do
List<Object> list = getObjectsFromDatabase();
This would not be the correct way to handle this?
But this would?
List<Object> firstList = getObjectsFromDatabase();
List<Object> list = new ArrayList<Object>(firstList);
Or if I had a class
public class ReportDisplayModel<T> {
public ReportDisplayModel(List<T> data) {
this.data = data;
}
public List<T> data;
}
And I wanted to set the data in this model I would use the constructor?
ReportDisplayModel<Object> model = new ReportDisplayModel<Object>(getData());
Instead of
ReportDisplayModel<Object> model = new ReportDisplayModel<Object>();
model.data = getData();
Just need a clarification. Thanks.
It depends entirely on what getData() returns.
usually it is made to return Collections.unmodifiableList(result) so that clients can't modify the result.
if this result is not used anywhere else, and modifications to it doesn't mess with anything, it is fine to use the result as-is
It is rarely needed to use the copy constructor - use it when you are sure that modifying the data will impact some other component.
Regarding
List<Object> list = getObjectsFromDatabase();
vs
List<Object> firstList = getObjectsFromDatabase();
List<Object> list = new ArrayList<Object>(firstList);
either approach is fine. Depends on if you want list to refer to the list returned by getObjectsFromDatabase() or if you want it to refer to a copy of it.
If simply want to, say, print the database objects, the first approach is fine.
If you want to, say, filter out half of the database objects (i.e., remove objects from the list), and you can't say for sure that getObjectsFromDatabase() returns a mutable list, then you'll have to go with the second approach.
Regarding
ReportDisplayModel<Object> model = new ReportDisplayModel<Object>(getData());
vs
ReportDisplayModel<Object> model = new ReportDisplayModel<Object>();
model.data = getData();
I'd prefer the first method. Simply because I wouldn't want to worry about null pointer exceptions etc if I accidentally do something like
ReportDisplayModel<Object> model = new ReportDisplayModel<Object>();
model.printData();
model.data = getData();
I don't quite get your question, but I'll give it a try.
The main difference is that using the copy constructor creates a new independent copy of the list, i.e.
List<Object> firstList = getObjectsFromDatabase(); // firstList is the list returned by the database
List<Object> list = new ArrayList<Object>(firstList); //list is an independent copy of firstList
Now if you change firstList the list returned by getObjectsFromDatabase() would be changed as well (or would throw an exception if changes are not supported). On the other hand list could freely be changed without the original list being affected.
Avoid using the equal sign, because it breaks encapsulation (bad practice). Go for the copy constructor (best practice).

Categories