I have an ArrayList of generic object type, i.e. List queue. I want to write a function EnqueueModified, that takes an arraylist and a list object as input and returns another ArrayList that contains the elments of the old arraylist and the list object but without affecting the original arraylist passed. i.e. Enqueue operation should be performed on a new copy of the arraylist and returned.
This can be done as follows:
public List<E> EnqueueModified(E e, List<E> queue) {
List<E> clone = new ArrayList<E>(queue);
clone.add(e);
return clone;
}
but is there a better method to do this? instead of using a copy constructor, is there any faster way to create a copy of the list? I cannot use cloning as it does not support for generic List.
To copy a list, you have to create a new list and fill it with items from the old list.
The constructor you are using might not actually be the best option, though. If you check the source code (google arraylist source code) you notice that it creates an array that is exactly as big as there are elements in the old collection.
Then it adds an element to that array. Because the array is too small, it has to create another copy of the array, only a bit bigger, and move the elements there again.
You could get a better performance by using
clone = new ArrayList(queue.size() + 1);
clone.addAll(queue);
clone.add(e);
Also, method names should start with a lower case letter. So use: enqueueModified(...)
Related
I have a collection c1<MyClass> and an array a<MyClass>. I am trying to convert the array to a collection c2 and do c1.removeAll(c2), But this throws UnsupportedOperationException. I found that the asList() of Arrays class returns Arrays.ArrayList class and the this class inherits the removeAll() from AbstractList() whose implementation throws UnsupportedOperationException.
Myclass la[] = getMyClass();
Collection c = Arrays.asList(la);
c.removeAll(thisAllreadyExistingMyClass);
Is there any way to remove the elements? please help
Arrays.asList returns a List wrapper around an array. This wrapper has a fixed size and is directly backed by the array, and as such calls to set will modify the array, and any other method that modifies the list will throw an UnsupportedOperationException.
To fix this, you have to create a new modifiable list by copying the wrapper list's contents. This is easy to do by using the ArrayList constructor that takes a Collection:
Collection c = new ArrayList(Arrays.asList(la));
Yup, the Arrays.asList(..) is collection that can't be expanded or shrunk (because it is backed by the original array, and it can't be resized).
If you want to remove elements either create a new ArrayList(Arrays.asList(..) or remove elements directly from the array (that will be less efficient and harder to write)
That is the way Array.asList() works, because it is directly backed by the array.
To get a fully modifiable list, you would have to clone the collection into a collection created by yourself.
Collection c = new ArrayList(Arrays.asList(la))
I have a collection c1<MyClass> and an array a<MyClass>. I am trying to convert the array to a collection c2 and do c1.removeAll(c2), But this throws UnsupportedOperationException. I found that the asList() of Arrays class returns Arrays.ArrayList class and the this class inherits the removeAll() from AbstractList() whose implementation throws UnsupportedOperationException.
Myclass la[] = getMyClass();
Collection c = Arrays.asList(la);
c.removeAll(thisAllreadyExistingMyClass);
Is there any way to remove the elements? please help
Arrays.asList returns a List wrapper around an array. This wrapper has a fixed size and is directly backed by the array, and as such calls to set will modify the array, and any other method that modifies the list will throw an UnsupportedOperationException.
To fix this, you have to create a new modifiable list by copying the wrapper list's contents. This is easy to do by using the ArrayList constructor that takes a Collection:
Collection c = new ArrayList(Arrays.asList(la));
Yup, the Arrays.asList(..) is collection that can't be expanded or shrunk (because it is backed by the original array, and it can't be resized).
If you want to remove elements either create a new ArrayList(Arrays.asList(..) or remove elements directly from the array (that will be less efficient and harder to write)
That is the way Array.asList() works, because it is directly backed by the array.
To get a fully modifiable list, you would have to clone the collection into a collection created by yourself.
Collection c = new ArrayList(Arrays.asList(la))
I have a List implementation (not mine) with an underlying array.
The implementation does not give access to the array directly, but only through the LIST INTERFACE methods that are implemented (just as an ArrayList implementation)
At some point, i will not able to work with this list (because of its implementation), but i will need to access (READ only) the data (underlying array).
Is there a way this can be achieved? Can a new ArrayList be created using the underlying array of the old one, without the creation of an ARRAY COPY?
You're going to have to have a new array to back the ArrayList anyway - so why is it a problem that it calls c.toArray()? The only inefficiency would be if it ends up in the branch calling Arrays.copyOf.
ArrayList(int) also creates an array
public ArrayList(int initialCapacity) {
...
this.elementData = new Object[initialCapacity];
}
but ArrayList(Collection) uses fast copying
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
My problem is I have an initial list called currentComponents. I am copying it's items in another new list called currentMonitorComponents. But when the components in currentMonitorComponents are modified automatically the items in currentComponents list are also modified. My code is something like this ---
List<MonitorComponent> currentMonitorComponents = new ArrayList<MonitorComponent>();
currentMonitorComponents.addAll(currentComponents);
You have to make a deep copy of your list:
ArrayList<MonitorComponent> currentComponentsClone = new ArrayList<MonitorComponent>();
for(MonitorComponent m : currentMonitorComponents)
currentComponentsClone.add(m.clone());
And to implement clone method in your class:
public class MonitorComponent{
String s;
Date d;
...
public MonitorComponent clone(){
MonitorComponent m = new MonitorComponent();
m.s = this.s.clone();
m.d = this.d.clone();
...
return m;
}
}
at the end these both have same elements(MonitorComponent).. they are pointing to same objects in memory.. You have to make clone of every MonitorComponent inside the list..
You will need to iterate on the items, and clone them one by one, putting the clones in your result arraylist as you go.
public static List<MonitorComponent> cloneList(List<MonitorComponent> list) {
List<MonitorComponent> clone = new ArrayList<MonitorComponent>(list.size());
for(MonitorComponent item: list) clone.add(item.clone());
return clone;
}
For that to work, obviously, you will have to get your MonitorComponent object to implement the Cloneable interface, and the clone() method.
What you are doing is creating a shallow copy. You have a new list, but the elements are the same objects, not copies of the objects. So if you modify one of the objects you can see the changes via both lists.
You could alternatively make a deep(er) copy, by creating new objects for your new list which are copies of the objects from the first list. The exact you'd do this will depend on the type of objects in question. One option may be to use clone(). Another might be to invoke a copying constructor. You'd need to do this for each element of the origina list, and add the copy to your new list.
When you "copy" elements from the original list to the new list, you're really copying the references contained in the original list, not the actual objects in the original list. Thus, the first element in each list really points at the same underlying object; thus, when you change that object using one list, the other list sees the change. It's sort of like having two "views" of the same underlying series of objects.
To fix this, you need to "clone" each of the objects you want to copy from the original list. There are a few ways of doing this, but in the end you have to be sure that at some point in your code the new keyword is used, clone() is called (the clone() method in Java, from what I've been told, though, should be avoided), or a constructor is called. That ensures that the objects you're putting into the second list are distinct from the originals.
I know that the Collection framework allows for the creation of "views", that is lightweight "wrappers" for a Collection object.
What I am especially interested in is, given a List, to return a view for only a subset of elements matching some conditions.
Basically, what I want to emulate is the functionality of the subList() method, only not based on start and end indexes, but on some parameters of the elements.
The first approach I thought about was simply to create another List, go through the first List and check each element...
While this wouldn't be actually copy any MyObject but only their references, I would anyways create a new List object, with its overhead. Isn't that right?
Is there any lightweight method of doing what I need?
N.B. My original List is a really big collection...
Thank you all
You can do this easily in Java using the Guava collections (Collections2 has a filter method http://docs.guava-libraries.googlecode.com/git-history/v11.0.1/javadoc/index.html).
You can also do this in groovy using the findAll method, for example
myList.findAll { it.contains("aValue") }
Any of these methods will create a new collection under the hood. So they are just doing the work for you of iterating over the elements and checking them. The overhead of creating a new list is minimal (it's just instantiating one new object).
I would anyways create a new List object, with its overhead
I don't understand what your concern here. Looking at source of ArrayList class even subList(int fromIndex, int toIndex) method in List class creates a new inner class (which extends from List). That is essentially what you will be doing in your method i.e. create a new List instance and copy your matching element's reference into it. That custom method will be more or less will have same performance as subList method.