Memory and performance of Java Arraylist - java

I have written Java code to get the list of employee name from database and storing it in a list.
List<String> employeeList = new ArrayList<Integer>();
employeeList = getAllEmployee();
My database changes regularly and number of employees increases or decreases daily.
Normally logic what can I use is getcount from DB and create Arraylist from that count.
I have a thought. Now if I have 3 employee from DB, If I create Arraylist I will create initial capacity of 10. Is there any way to remove the unused space 7 from ArrayList. Also please enlighten me on initial capacity algorithm and load factor too.

Yes, there is a way to remove the unused space. You can use the method trimToSize(), which, according to its Javadoc,
trims the capacity of this ArrayList instance to be the list's current size.
Note that this requires downcasting a List to an ArrayList, by the way.
The current implementation of ArrayList in Oracle's Java 8 runtime has a private method grow(). You can see the implementation if you have a JDK installed, I suppose. It doesn't work with a 'load factor' but uses a different algorithm for determining the new capacity of the underlying array:
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
Plus it does some boundary checking to make sure the ints do not overflow, but that's a different story.

i think this is what you are looking for java.util.ArrayList.trimToSize() method , that trims the capacity of an ArrayList instance to the current size. it will minimize the storage of an ArrayList instance
doclink

You can create a list with a size equals to the desired size.
List<String> list = new ArrayList<String>(desiredSize);
Please note that the code you wrote
List<String> employeeList= new arrayList()<Integer>;
employeeList= getAllEmployee();
probabilly create two lists. One explicitly, the second inside the code of getAllEmployee(). So the best is
List<String> employeeList = getAllEmployee()
and in your getAllEmployee code do something like that
public List<String> getAllEmployee() {
...
int desiredSize = ....
...
List<String> list = new ArrayList<String>(desiredSize);
...
return list;
}
Note that if you are not in an extremely optimized environment (and I think you aren't otherwise you didn't asked for this kind of problem) it is not necessary to save few bytes. If the code is less readable and you have to calculate the desired size with an additional call to the database is not a good programming choice.

Related

Best way to read data from a file and store them

I am reading data from a file of students where each line is a student, I am then turning that data into a student object and I want to return an array of student objects. I am currently doing this by storing each student object in an arraylist then returning it as a standard Student[]. Is it better to use an arraylist to have a dynamic size array then turn it into a standard array for the return or should I first count the number of lines in the file, make a Student[] of that size then just populate that array. Or is there a better way entirely to do this.
Here is the code if it helps:
public Student[] readStudents() {
String[] lineData;
ArrayList<Student> students = new ArrayList<>();
while (scanner.hasNextLine()) {
lineData = scanner.nextLine().split(" ");
students.add(new Student(lineData));
}
return students.toArray(new Student[students.size()]);
}
Which is better depends on what you need and your data set size. Needs could be - simplest code, fastest load, least memory usage, fast iteration over resultind data set... Options could be
For one-off script or small data sets (tens of thousands of elements) probably anything would do.
Maybe do not store elements at all, and process them as you read them? - least memory used, good for very large data sets.
Use pre-allocated array - if you know data set size in advance - guaranteed least memory allocations - but counting elements itself might be expensive.
If unsure - use ArrayList to collect elements. It would work most efficiently if you can estimate upper bound of your data set size in advance, say you know that normally there is not more than 5000 elements. In that case create ArrayList with 5000 elements. It will resize itself if backing array is full.
LinkedList - probably the most conservative - it allocates space as you go but required memory per element is larger and iteration is slower than for arrays or ArrayLists.
Your own data structure optimized for your needs. Usually the effort is not worth it, so use this option only when you already know the problem you want to solve.
Note on ArrayList: it starts with pre-allocating an array with set of slots which are filled afterwards without memory re allocation. As long as backing array is full a new larger one is allocated and all elements are moved into it. New array size is by default twice the size of previous - normally this is not a problem but can cause out of memory if new one cannot get enough contiguous memory block.
Use an array for a fixed size array. For students that is not the case, so an ArrayList is more suited, as you saw on reading. A conversion from ArrayList to array is superfluous.
Then, use the most general type, here the List interface. The implementation, ArrayList or LinkedList then is a technical implementation question. You might later change an other implementation with an other runtime behavior.
But your code can handle all kinds of Lists which is really a powerful generalisation.
Here an incomplete list of useful interfaces with some implementations
List - ArrayList (fast, a tiny bit memory overhead), LinkedList
Set - HashSet (fast), TreeSet (is a SortedSet)
Map - HashMap (fast), TreeMap (is a SortedMap), LinkedHashMap (order of inserts)
So:
public List<Student> readStudents() {
List<Student> students = new ArrayList<>();
while (scanner.hasNextLine()) {
String[] lineData = scanner.nextLine().split(" ");
students.add(new Student(lineData));
}
return students;
}
In a code review one would comment on the constructor Student(String[] lineData) which risks a future change in data.

Can the size of an ArrayList be changed after it is initialized?

In a practice test in a class I'm taking there is the following question:
True or False. The size of an ArrayList cannot be changed after the ArrayList is initialized.
Immediately looking at the question, I would think the answer would be false. If you initialize an ArrayList, you can continue adding unlimited elements to it and the ArrayList will automatically resize. However, the answer key claims the answer is true. Why would this be? Is there something going on behind the scenes that I'm not understanding?
Edit: The instructor told me it was in fact an error in the answer key. Thank you for all the help.
False. To quote from javadoc, it explains array list to be a
Resizable-array implementation of the List interface.
Further it also explains
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.
Also, for an ArrayList, size can not be set while initializing. However the initial capacity can be set. Size is the number of elements in the list.
Yes. setting a value just puts an initial length. if you try to add an element to a "full" List, it will increase in size. only Arrays are fixed in size.
EDIT:
True or False. The size of an ArrayList cannot be changed after the
ArrayList is initialized.
This statement is false. The size can be easily altered by adding more elements.
Remember.. there are 2 things involved..
capacity and size..
capacity represents how many max elements the list can
accomodate in it, size represents how many elements are
present currently in the list..the capacity is automatically
increased by certain amount (10, 20, 30..) based on the
current size once the size is equal to capacity..
In case of the question you have been asked, if this is the code in question, the size cannot be altered... (Common java question)
public static void main(String[] args) {
int []a = {1,2,3};
List l = Arrays.asList(a);
l.add(4); //error java.lang.UnsupportedOperationException
System.out.println(l);
}
It could be true (in a twisted way), if it takes into account the fact that a new array is created (and the datas of the old one copied into it) in the ArrayList if the size is reached. But it would be like saying that because you replace a part in a computer it's a new one.
I believe you should just go ask for an explanation of the answer.
False, Arraylist in java can be changed all the time when you do add or remove to a element of the list
Size of an Array is not dynamic. It does not grow.
In order to overcome this, Collections has come up with this feature.
ArrayList size is dynamic. If we initialize it with an initial capacity, it would create an arraylist of the same capacity. If the code adds more than the initial capacity, based on the load factor, the size would increase.
Here is an example which explains this:
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<String> arr= new ArrayList<String>(2);
arr.add("apple");
arr.add("apple");
arr.add("apple");
System.out.println(arr);
}
No error from the above code. It prints the ArrayList.
Console Output
[apple, apple, apple]
As per your question, when you initialize an Arraylist[here i gave the capacity as 2], size is 0 (i.e. arr.size() is 0) but if you print the size after the Arralylist is assigned with "apple", the size would be 3.

to compare the memory usage between the use of the static array and java.util.ArrayList in a sorting operation

Runtime rt = Runtime.getRuntime();
long totalM = rt.totalMemory();
long currentM;
int []n = new int[10000];
System.out.print("10000 ints used: ");
System.out.println(totalM - rt.freeMemory());
Its not working. We cannot use long for calculation?
Thanks in advance, Please give me some suggestions
Answering the implicit question in the title: What is difference in "memory usage between the use of the static array and java.util.ArrayList in a sorting operation".
In Java 8: None. This is because the sort is delegated to the ArrayList class, which sorts the backing array directly using Arrays.sort().
In Java 7 and below, the list is converted to an array, the array is sorted, and the result is put back into the list. So, memory is doubled for the array, plus whatever extra memory is need by the sorting operation itself, which depends on the version of Java.
This is also what happens for LinkedList in Java 8.

How to merge two big Lists in one sorted List in Java?

I had an interview today, and they gave me:
List A has:
f
google
gfk
fat
...
List B has:
hgt
google
koko
fat
ffta
...
They asked me to merge these two list in one sorted List C.
What I said:
I added List B to List A, then I created a Set from List A, then create a List from the Set. The interviewer told me the lists are big, and this method will not be good for performance, he said it will be a nlog(n).
What would be a better approach to this problem?
Well your method would require O(3N) additional space (the concatenated List, the Set and the result List), which is its main inefficiency.
I would sort ListA and ListB with whatever sorting algorithm you choose (QuickSort is in-place requiring O(1) space; I believe Java's default sort strategy is MergeSort which typically requires O(N) additional space), then use a MergeSort-like algorithm to examine the "current" index of ListA to the current index of ListB, insert the element that should come first into ListC, and increment that list's "current" index count. Still NlogN but you avoid multiple rounds of converting from collection to collection; this strategy only uses O(N) additional space (for ListC; along the way you'll need N/2 space if you MergeSort the source lists).
IMO the lower bound for an algorithm to do what the interviewer wanted would be O(NlogN). While the best solution would have less additional space and be more efficient within that growth model, you simply can't sort two unsorted lists of strings in less than NlogN time.
EDIT: Java's not my forte (I'm a SeeSharper by trade), but the code would probably look something like:
Collections.sort(listA);
Collections.sort(listB);
ListIterator<String> aIter = listA.listIterator();
ListIterator<String> bIter = listB.listIterator();
List<String> listC = new List<String>();
while(aIter.hasNext() || bIter.hasNext())
{
if(!bIter.hasNext())
listC.add(aIter.next());
else if(!aIter.hasNext())
listC.add(bIter.next());
else
{
//kinda smells from a C# background to mix the List and its Iterator,
//but this avoids "backtracking" the Iterators when their value isn't selected.
String a = listA[aIter.nextIndex()];
String b = listB[bIter.nextIndex()];
if(a==b)
{
listC.add(aIter.next());
listC.add(bIter.next());
}
else if(a.CompareTo(b) < 0)
listC.add(aIter.next());
else
listC.add(bIter.next());
}
}

Starting Size for an ArrayList

I want to use an ArrayList (or some other collection) like how I would use a standard array.
Specifically, I want it to start with an intial size (say, SIZE), and be able to set elements explicitly right off the bat,
e.g.
array[4] = "stuff";
could be written
array.set(4, "stuff");
However, the following code throws an IndexOutOfBoundsException:
ArrayList<Object> array = new ArrayList<Object>(SIZE);
array.set(4, "stuff"); //wah wahhh
I know there are a couple of ways to do this, but I was wondering if there was one that people like, or perhaps a better collection to use. Currently, I'm using code like the following:
ArrayList<Object> array = new ArrayList<Object>(SIZE);
for(int i = 0; i < SIZE; i++) {
array.add(null);
}
array.set(4, "stuff"); //hooray...
The only reason I even ask is because I am doing this in a loop that could potentially run a bunch of times (tens of thousands). Given that the ArrayList resizing behavior is "not specified," I'd rather it not waste any time resizing itself, or memory on extra, unused spots in the Array that backs it. This may be a moot point, though, since I will be filling the array (almost always every cell in the array) entirely with calls to array.set(), and will never exceed the capacity?
I'd rather just use a normal array, but my specs are requiring me to use a Collection.
The initial capacity means how big the array is. It does not mean there are elements there. So size != capacity.
In fact, you can use an array, and then use Arrays.asList(array) to get a collection.
I recomend a HashMap
HashMap hash = new HasMap();
hash.put(4,"Hi");
Considering that your main point is memory. Then you could manually do what the Java arraylist do, but it doesn't allow you to resize as much you want. So you can do the following:
1) Create a vector.
2) If the vector is full, create a vector with the old vector size + as much you want.
3) Copy all items from the old vector to your new vector.
This way, you will not waste memory.
Or you can implement a List (not vector) struct. I think Java already has one.
Yes, hashmap would be a great ideia.
Other way, you could just start the array with a big capacity for you purpose.

Categories