Can I use ArrayList.trimToSize() method in dynamic arrayList ?
If I use it , what will be happened ?
Can I get any benefits on using this method on dynamic ArrayList.
In which case, I should use this method.
Thanks in advance.
From the docs you link yourself:
Trims the capacity of this ArrayList instance to be the list's current size. An application can use this operation to minimize the storage of an ArrayList instance.
Internally an ArrayList stores an array that holds all the items. At certain moments the ArrayList will "expand" this array by copying all values into a larger array. This happens whenever an item is being added and the required capacity is bigger than the current one. What happens at this point is the following line of code:
int newCapacity = oldCapacity + (oldCapacity >> 1);
elementData = Arrays.copyOf(elementData, newCapacity);
In essence this will create a new array that is 1.5 times the size of the current one. What this method does is resize the internal array so that it has no empty space left.
Nothing will happen that's visible to you. You won't lose any data, it's just smaller backing array. Adding data to the arraylist will again expand the array normally.
I assume you mean a "normal" ArrayList. If you use this, you will reduce the memory used but it will also be futile if you will still add data after that AND it is pretty useless for small lists. If you have an ArrayList of many, many items and you're sure you don't want to add anymore then you can call this method to reduce some memory footprint.
See above. I don't think it's very likely you'll ever use this.
trimToSize() from the source:
public void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
}
Well, that's simple:
The ArrayList will be trimmed to its current size
Yes, you can minimize the storage of an ArrayList instance
When you want to trim the ArrayList and minimize its storage
But seriously: There are few occasions where this method should be called (I personally have never used it). It's related to how an ArrayList is implemented: As the name suggests, the ArrayList internally uses an array to store the data. When you add new elements to the ArrayList, the size of the array is increased as needed. When you add 1000000 elements to the ArrayList, then the internal Array will have a .length of at least (!) 1000000. When you afterwards remove 999999 elements from the ArrayList, then the internal array will still have a .length of at least 1000000. The call to trimToSize will then make sure that the internal array only has the required size (1, in this case). But again: This is hardly ever necessary or beneficial. You should usually not work on ArrayList instances anyhow, but on the (more general) List interface.
Related
I need to create an array of several hundred objects. MyObject has a large memory footprint, takes as bit of effort/time to create and will be created one at a time. I know how many when I start. I can create an array MyObject[n] sized appropriately then insert the MyObject via an index. Or I can create an ArrayList<MyObject> then do an add(MyObject). The code size and structure is similar but I can imagine the second method 'could' fragment the memory differently than the first method. (Really?) I suppose the difference is pretty small, especially considering there are less than 1000 entries, but my guess is that the first method is better as it uses information I have earlier in the process. Does the ArrayList.add() have to do extra work to increase its size?
If you check the implementation of add(E e) inside the class ArrayList, you can see this:
public boolean add(E e) {
modCount++;
add(e, elementData, size); //check below
return true;
}
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
So basically, the only time when ArrayList.add() does something more than simply setting an element inside the E[] array that it holds, is when s == elementData.length.
If you check what these fields are:
elementData: "The array buffer into which the elements of the ArrayList are stored. The capacity of the ArrayList is the length of this array buffer"
size: "The size of the ArrayList (the number of elements it contains)."
So, if you check the constructor public ArrayList(int initialCapacity), you can see that when you provide an initial capacity, the array elementData will be initialized with the capacity you provide:
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
Which, in other words, means that the if (s == elementData.length) condition will never be met if you know in advance the number of elements that you will store in the array, and so the elementData = grow() will never be called making the usage of .add() method basically equivalent to you manually setting each element inside the array by index.
To sum up, if you know that you will store 850 elements in your list, then doing this:
List<Element> elements = new ArrayList<>(850);
elements.add(element1);
elements.add(element2);
//...
elements.add(element850);
... is practically equivalent, operations-wise, than doing the set into an array yourself (there is one if-check and one increment more but that's really irrelevant). With the advantage though that you have a structure such as List that makes the object much easier to use (you'll be able to use iterators and all other features provided by List interface).
So especially when the number of elements is so small (< 1000) and that you know how many they are in advance, I wouldn't overthink it and go directly into an ArrayList.
elementData = grow() is super crucial. ArrayList uses the double-and-copy strategy to amortize the cost of insertion. When it hit's the length of it's internal buffer it creates a new array of double the size of the last and copies in the old data. So, add(x) amortizes to O(1) (constant) because over the course of enough adds, it averages to a constant insertion time.
I mean, think about this logically:
Why on earth offer an initialSize in the constructor if it's of no consequence?
How can it continue to just accept data and behave like an array?
But, he is right: unless you're working with a huge list and perpetually updating it, its of no consequential effect
I am a somewhat experienced Java developer and I keep seeing things like this
List<Integer> l = new ArrayList<Integer>(0);
which I really can't understand. What's the point of creating an ArrayList with an initial capacity of 0, when you know it's going to grow beyond the capacity?
Are there any known benefits of doing this?
It keeps the size (in memory) of the ArrayList very small, and is a tactic for when you want the variable to be non-null and ready to use, but don't expect for the List to be populated immediately. If you expect it to be populated immediately, it's best to give it a larger initial value - any "growing" of the ArrayList is internally creating a new primitive array, and copying items over. Growth of an ArrayList is expensive, and should be minimized.
Or, if you're creating lots of instances of a class that each contain one of these List properties. If you don't immediately plan on filling them, you can save a bit of memory by not allocating the room just yet.
However: There is a better way: Collections.emptyList(). Normally you'll want to protect access to that list directly, and (as an example) in your class provide domain-specific method calls that operate on the internal List. For example, let's say you have a School class that contains a List of student names. (Keeping it simple, note this class is not thread safe.)
public class School {
private List<String> studentNames = Collections.emptyList();
public void addStudentName(String name) {
if (studentNames.isEmpty()) {
studentNames = new ArrayList<String>();
}
studentNames.add(name);
}
public void removeStudentName(String name) {
studentNames.remove(name);
if (studentNames.isEmpty()) {
studentNames = Collections.emptyList(); // GC will deallocate the old List
}
}
}
If you're willing to make the isEmpty() checks and perform the initialization/assignment, this is a better alternative to creating lots of empty ArrayList instances, as Collections.emptyList() is a static instance (only one exists) and is not modifiable.
For java 6 (or openjdk 7), not specifying an initial size gives you a list within initial size set to 10. So depending on many factors of your usage of the list, it could be very slightly more memory and/or performance efficient to initialize the list with size 0.
For java 7, specifying an initial size 0 is functionally equivalent to not specifying an initial size.
However it is actually less efficient, since the call to the constructor with argument 0 incurs a call to new Object[0], whereas if you specify the no-args constructor, the initial elementData for your list is set to a statically defined constant named EMPTY_ELEMENTDATA.
Relevant code from ArrayList source:
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
In other words the use of new ArrayList<Integer>(0); seems superfluous, there are no benefits to doing so, and I would use new ArrayList<Integer>(); instead.
If additions to that ArrayList are really unlikely and if it's important to keep the size of the ArrayList at a minimum, then I can see that being useful.
Or if the only purpose of that ArrayList is to be a return value from a method, where returning an empty list is a special message to the function caller, like "no results found".
Otherwise, not really.
By default ArrayList has capacity of 10 and it is resized by +50% each time.
By using lower initial capacity you can sometimes(in theory) save memory. On the other hand each resize is time consuming. In most cases it is just a sign of preemptive optimization.
It's always better approach to give a large value(if you how much list will exceed) to array list, because it will reduce resizing of list and hence optimize your execution time.
Initializing array list with value 0 create Empty array list which reducing memory if you know your list will not present more then 10 content's.
Depending on the contract you can avoid NullPointerExceptions by not having nulls. It is good practice in certain situations, see Effective Java by Joshua Bloch Item 43: Return empty arrays or collections, not nulls
in java, if we store 4 elements in array and array list, is it same at low level in memory OR does it make any difference in order to store elements ?
It's going to be different. An ArrayList is a wrapper around the array with several other helper functions. The memory footprint is going to be a little bit bigger for ArrayList, and it will resize itself as necessary.
It differs, ArrayList internally manages its own array for storage and has own attributes also
An array is pretty different from a List, even if the list happens to be an ArrayList and internally uses just an array as well.
For the array there exists just the array (for this discussion I'll ignore the memory the elements will occupy). Thus you have one object in the heap, the array itself.
For the ArrayList, there exists the ArrayList instance and that instance internally has an array. So there are two objects on the heap. Also, while you have exact control over the size of an array you create, the array held by the ArrayList can have any size that is >= number of elements <= Integer.MAX_VALUE.
Coincidentily, ArrayList uses an elements index directly as array index internally, so the order of elements is the same as in a plain array. But thats an implementation detail, and you normally don't care how a List organizes its data internally (after all the purpose of Lists is to abstract the messy details away).
I come from a C++ background and I want to have a matrix of
ArrayList<arrayList<E>> javamatrix
In C++ I would just do
std::vector<std::vector<T> > cppmatrix;
std::vector<T>vcol(cols);
cppmatrix.resize(rows,vcol);
I can't seem to find a built-in resize() function for ArrayLists for this task, so should I use another collection? Is no way to do this except using for loops with javamatrix.add()?
P.S I want it to be initialized in the constructor with its size as that size might be queried before I edit elements or add or remove.
There is no resize equivalent that automatically constructs and adds elements. You must do this yourself. However, ensureCapacity is equivalent to vector's reserve. It will ensure you have room, but not change the actual size.
You shouldn't need to resize arraylists. The size you initially pass in is just its starting size. If you attempt to add items beyond its current size, it will automatically resize.
From the documentation:
Each ArrayList instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. As elements are added to an ArrayList, its capacity grows automatically. The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.
Mostly, a 'resize()' operation is not needed because (a) ArrayList's auto-resize as you add elements, and (b) it's unclear what values you would store in the ArrayList<>, e.g. 'null' is not very useful. E.g. in your case you'd probably need a loop anyway to create MatrixCell objects.
For those readers who want to know how to resize an ArrayList to make it smaller, it mystifies me why ArrayList was designed without a 'resize()' method. Perhaps it's because novice programmers are likely to see that method and then not realise that ArrayList<> auto-resizes.
In Java this idiom works to reduce the size of an ArrayList<>:
list.subList(n,list.size()).clear();
It works because the 'subList' returns a List backed by the original ArrayList<>, so therefore the 'clear()' operates on the original 'ArrayList<>'.
I know this question is very old already but this link may help java arraylist ensureCapacity not working , The code adds "Null" value in order to adjust the current size.
Instead of using purely ensureCapacity you can have ensureSize
public static void ensureSize(ArrayList<?> list, int size) {
list.ensureCapacity(size);
while (list.size() < size) {
list.add(null);
}
}
I've got a Problem with ArrayList. I need it to store a result. Because I want to start with element n I tried to give the ArrayList a capacity with ensureCapacity(n+1) to use set(n,x) but I get an IndexOutOfBoundsException.
I tried to store n add(x) before the use of set and this works.
So I'd like to know why it doesn't work on my way and how to solve this because put n times a add(x) isn't a good style ;-)
When you change the capacity of an ArrayList it doesn't create any elements, it just reserves memory where there could be elements. You can check the size before and after adjusting the capacity and you will see that it does not change.
The purpose of changing the capacity is if you know in advance how many elements you will have, then you can avoid unnecessary repeated resizing as you add new elements, and you can avoid memory wastage from excess unused capacity.
If you don't like using your own loop and the list add method directly then there is another way. Create your ArrayList with the number of elements you want it directly like this:
final int MAX_ELEMENTS = 1000;
List<Integer> myList = new ArrayList<Integer>(
Collections.<Integer>nCopies(MAX_ELEMENTS, null));
Or, if you already have a list that you want to expand the size by n elements:
myList.addAll(Collections.<Integer>nCopies(n, null));
(Note, I assumed here that the list would be holding Integer objects, but you can change this to your custom type. If you are working with raw/pre-Java 5 types then just drop the generic declarations.)
As for your actual question: capacity != contents. An ArrayList internally has both a physical array and a count of what is actually in it. Increasing the capacity, changes the internal array so it can hold that many elements, however, the count does not change. You need to add elements to increase that count.
On the other hand, if you are just trying to set specific elements and know the maximum that you want to use, why not use an array directly? If you then need to pass this array to an API that takes Lists, then use Arrays.asList. The other classes could still change contents of your backing array but it would not be able to increase the size or capacity of it.
As others have answered, ensureCapacity() is just related to performance, is not frequently used by the common user.
From Bruce Eckel's Thinking in Java book:
In a private message, Joshua Bloch
wrote: "... I believe that we erred by
allowing implementation details (such
as hash table size and load factor)
into our APIs. The client should
perhaps tell us the maximum expected
size of a collection, and we should
take it from there. Clients can easily
do more harm than good by choosing
values for these parameters. As an
extreme example, consider Vector's
capacityIncrement. No one should ever
set this, and we shouldn't have
provided it. If you set it to any
non-zero value, the asymptotic cost of
a sequence of appends goes from linear
to quadratic. In other words, it
destroys your performance. Over time,
we're beginning to wise up about this
sort of thing. If you look at
IdentityHashMap, you'll see that it
has no low-level tuning parameters"
You are getting this exception because ensureCapacity() only makes sure that there is enough memory allocated for adding objects to an ArrayList, I believe this is in case you want to add multiple objects at once, without having to relocate memory.
To do what you want you would have to initiate the ArrayList with null elements first...
int n = 10; //capacity required
ArrayList foo = new ArrayList();
for( int i=0; i<=n; i++ ) {
foo.add(null);
}
Then you have objects in the List that you can reference via index and you wont receive the exception.
Perhaps you should rethink the choice of using List<Double>. It might be that a Map<Integer,Double> would be more appropriate if elements are to be added in an odd order.
Whether this is appropriate depends on knowledge about your usage that I don't have at the moment though.
Is the data structure eventually going to be completely filled, or is the data sparse?
what other people said about ensureCapacity() ...
you should write a class like DynamicArrayList extends ArrayList. then just overrride add(n,x) to do with for loop add(null) logic specified about.
ensureCapacity() has another purpose. It should be used in cases when you get to know the required size of the List after it has been constructed. If you know the size before it is constructor, just pass it as a an argument to the constructor.
In the former case use ensureCapacity() to save multiple copying of the backing array on each addition. However, using that method leaves the structure in a seemingly inconsistent state
the size of the backing array is increased
the size field on the ArrayList isn't.
This, however, is normal, since the capacity != size
Use the add(..) method, which is the only one that is increasing the size field:
ArrayList list = new ArrayList();
list.ensureCapacity(5); // this can be done with constructing new ArrayList(5)
for (int i = 0; i < list.size - 1; i ++) {
list.add(null);
}
list.add(yourObject);