How to correctly clear list in java - java

Lets say I have a list like this:
private LinkedList<String> messages = new LinkedList<String>();
When my method gets invoked for the first time there some strings added to this list. And I have also another method in which I need to clear this list from previously added values. To clear it I can use:
messages.clear();
This will remove all the elements from the list. Also I can create a new instance like this:
messages = new LinkedList<String>();
Which way is more proper to clear the list?

messages.clear();
Will actually clear the list, messages = new LinkedList<String>(); will just set messages as referencing a new list instance, so you could argue the first way is more "correct" to clear the list instance.

Say you have a list that is referenced by two variables, a and b. Like this (they don't have to be as close to eachother as this, they might even be in different files..):
final List<String> a = new LinkedList<String>();
final List<String> b = a;
Now, there is a big difference between
a.clear();
which will make both a and b reference the same, empty list, and
a = new LinkedList<String>();
which will make 'a' reference a new, empty list, and 'b' the old, populated list. (So they do not reference the same list).
Since you probably want them to reference the same list, a.clear() is preferred, since you won't get any surprises when your looking at the list referenced by b (which you might believe to be empty, but turns out to be populated if you use the new-approach).

I prefer the first approach i.e. messages.clear(); as it clear the elements but the List is not destroyed and recreated. All elements are removed as desired.
One side effect is there though: It iterates your list and removes one item at a time so if the list is huge then it's an unnecessary overhead.
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
Same way second approach has also one side effect: If you are using the object reference of you r list somewhere else in your program, that needs to handled properly otherwise you could get some unwanted surprises e.g. if you added your list to some other object/variable, then first approach will clear that elements from every place where it was referenced while second will not.
Summary: Both the approach outcomes are different in low level nature; though they seem to to serve your high level requirement (clearing the list). Decide carefully based on your low level requirements.

They are almost similar, but I would say messages.clear() is more flexible.
The second approach is simple and much used, but the problem where you have final modifier on your list you can not clear it that way.

messages.clear();
is more efficient. For more safety you can ask if this list is not empty befor

Personnaly I prefere to use LinkedList#clear because it is more clearly to understand during reading the code what you are doing.
But the new LinkedList<String>(); will work fine as well. So it's up to you what to use!

It clearly depends upon your need.
If you want to keep reference to your list object instance (as an example if that clear method is called inside a method in which the messages is a parameter, then the call to .clear() is the best solution.
On the other hand, if the list you want to clear is a member field (or a local variable in a method) of the object the current method is a member of, then you can call new LinkedList<String>(); without any trouble.
Notice that, to avoid the first (which I tend to disapprove), i usuall always return obejcts I modify as results from methods modifying them.

the first one is preferable. the second one makes some extra burden on the garbage collector. but the first one not.

Related

Storing an Object into a temporary Object and not changing the original Objects value

I have an object stored in a global variable let's say:
static ArrayList<Object> list = new ArrayList<Object>();
I want to store it later to look into it without actually changing the values in the structure itself. So I am doing something similar to this:
public void someMethod()
{
ArrayList<Object> tempList = new ArrayList<Object>();
tempList = list;
list.remove(0);
}
I'm thinking this may have something to do with me initializing the variable as "static". I don't usually do that but Eclipse told me I had to so I just let the change happen.
My understanding would be that I am storing the original list into a temporary list and anything I do to the temporary list would be independent of the original list. But it appears that if I were to remove something from this above list, that the original list is removing it as well.
I remember learning that this could happen sometimes but I think I've done this before without having that issue.
I apologize if this is a repeated question but the way I worded it didn't show me an question that was similar.
Thanks!
My understanding would be that I am storing the original list into a temporary list and anything I do to the temporary list would be independent of the original list.
This is not the case. When you do something like
a = b;
then both a and b refer to the same object. Mutations in a show up in b and vice verse (since there is only a single object in question). In this case you probably want to use the copy constructor of ArrayList:
ArrayList<Object> tempList = new ArrayList<Object>(list);
Notice that here we are explicitly creating a new, independent object and assigning that to tempList.
Note that this creates what's called a shallow copy: the objects referenced by the list themselves are not copied, but instead a new list is created that contains the references to the same objects as the original list.
At the end of your someMethod, your tempList disappears into the dark void of the GC. If you want to keep it, you need to turn it into a similar field as list is.
Also, assigning list to tempList makes you have two references to the same object.

concurrent hashmap and copyonwritearraylist

I am trying to populate a cache which hold the key/value with ConcurrentHashMap.
I am assuming using a CopyOnWriteArrayList takes care of concurrency and I have that as my value for my key, but I am missing something in the below code and it is overriding its values when multiple threads are executing.
if (testMap.get(id) == null) {
CopyOnWriteArrayList<String> copyArr = new CopyOnWriteArrayList<String>();
copyArr.add("Add Value");
testMap().putIfAbsent(id, copyArr);
} else {
testMap.put(id,testMap.get().add("Append Value"));
}
How do I protect the code which creates the CopyOnWriteArrayList from multiple threads.
Here is the revised version of code as per the suggestions below.
CopyOnWriteArrayList<Subscriber> subscriberArr = CacheUtils.getSubscriberMap().get(syncDet.getCardNumber());
if (subscriberArr == null) {
subscriberArr = new CopyOnWriteArrayList<Subscriber>();
CopyOnWriteArrayList<Subscriber> refArr =
cacheUtils.getSubscriberMap().putIfAbsent(syncDet.getCardNumber(), subscriberArr);
if (refArr != null) {
subscriberArr = refArr;
}
}
subscriberArr.add(syncDet.getSubScriber());
On iterating the subscriber map i dont see a value object. size is 0 .
You need to first retrieve the appropriate list then populate it. Something like:
List<String> copyArr = testMap.get(id);
if (copyArr == null) {
copyArr = new CopyOnWriteArrayList<String>();
List<String> inMap = testMap.putIfAbsent(id, copyArr);
if (inMap != null) copyArr = inMap; // already in map
}
copyArr.add("Add Value");
That way you only put a new list in the map if there wasn't already one and you add your item to whatever list has made it to the map.
There are a couple of problems with the implementation you made.
Firstly, you are checking whether there is no list for a given key in a non-thread-safe way. It can entirely happen that two threads can execute if (testMap.get(id) == null) before any of them puts the key. This will not cause the key to be overriden per se.
However, both lists are generated, and since you're adding elements to those lists in the unsafe if block prior to the setting of the key, what elements wind up in the actual key->value mapping is anyone's guess.
Also, there's absolutely no need for this:
testMap.put(id,testMap.get(id).add("Append Value"));
The list instance is already in the map in this case, you just need to get it and add the value. Note that this may also mess up your previous key assignment!
The second, potential problem is that you're using a CopyOnWriteList which creates a new backing array on adding new elements. Two consequences here:
it's expensive if there are a lot of additions.
since the add operation is synchronized (through a ReentrantLock), but get isn't, you may get different list contents in different threads for a short time (the list is eventually consistent for addition, however). This is actually by design - CopyOnWriteArrayList is geared towards hi-read/lo-write operations.
You've got at least two ways out here:
conduct put operations in a thread-safe manner, i.e.
use only putIfAbsent.
don't add any values to the local copy of the list, just the one you take from get.
if you need absolute instead of eventual consistency, don't use a CopyOnWriteArrayList at all. Use a normal list with "manual" synchronization instead. You can use e.g. Guava's Multimap's, such as this one, with a synchronization wrapper to save you the trouble (the Javadoc explains how).

Need to use "new" when adding to a List?

I'm new to Java and been trying to figure out if I need to pass a new instance of a class when adding the entry to a list, as such:
CCustEntry entry = new CCustEntry();
List<CCustEntry> CustList = new ArrayList<CCustEntry>();
do
{
// set all entry fields
entry.id = [...];
[fill other fields of entry from DB]
// add entry (constructor copies entry)
CustList.add( new CCustEntry( entry ) );
} while( C.moveToNext() == true );
OR... can I remove new and simply pass entry to the add() method like this:
CustList.add( entry );
I've been reading about Lists but I'm more confused than I was before. Coming from Delphi and C++, I'm fine with the syntax, but some of the "grammar" of Java still has me scratching my head.
Thanks for any help.
It depends if the entry will be modified or not. It sounds like you have a bean that makes a shallow copy of the entry, so if the fields of entry will be modified, then you should add a copy. Otherwise, it would be just wasting memory to construct a new one.
Here, it seems like you are using the same entry throughout the loop, so you will want to make a copy. Otherwise, the whole list will contain the same object - i.e., each item is the same object.
Another comment: in Java, it's usual to name fields and values starting with a lowercase letter.
It depends: if you don't create a new instance each time, then you will be adding the same instance to the list multiple times. This means that if you modify an element at one index of the list, then all of the other elements will also get modified in the same way (since they are all the same instance). If you want distinct but equal instances, then you must create a new one each time.

What's best for array reinitialization : set to null by iteration or simply allocate a new array?

In my code, I have an array that has about 1000 elements :
Object[] arr = new Object[1000];
After my array is populated (the whole array or just partially), I need to reinitialize it. From what I know, I have two choices : to initialize it by new keyword, or to iterate over it and set each element to null. I think first approach is best than second, but also I'm waiting for your thoughts.
Any links or articles on this topic are welcome.
Thanks in advance
First one is better. By reinitializing it with new keyword, you put the previous set of array eligible for garbage collection by providing a path to GC (assuming that other live objects does not have a reference to any of them).
The second one would achieve the same effect eventually, but there is an added performance hit because you need to iterate one by one. For 1000 records, this would likely happen very fast, but if the number grows then the hit would be greater.
Agree with your first choice use arr = new Object[1000] and don't loop it.
Also the use of new Object[1000] doesn't create 1000 objects it only makes a "placeholder" for 1000 objects so it's a very cheap operation.
And if you know you will populate all 1000 objects you can just use the array as is without reinitializing it.
First is the best way Object[] arr = new Object[1000];
also you can find in below link, number of ways array can be initialised
array initialisation
First by setting the array to null you effectively tell the GC it can check everything in that array and clean it up if necessary. So there is no need to iterate through the elements, even if you arent going to do a new right away.
That being said, the only time you really would ever explicitly need to set a variable(for GC purposes anyway) to be explicitly NULL is if you no longer need the data pointed to by that variable, but have nothing new to put in its place AND the variable, for whatever reason, will stay in scope for a while. In that case its advisable to set the value to null, or better yet, re-work your code so that variable goes out of scope and that is done for you.
So for instance, in your example say arr was a static member of some class and you just needed to do some processing on the array at startup and never look at it again. In that case, the contents of arr will stick around for the entire time your program is running UNLESS you explicitly set it to null(or assign it a new value).

Java clearing a list by creating a new instance

I was looking through Java code, and I came across this code:
list = new ArrayList();
uselist(list);
if (condition)
list = new ArrayList();
What's the use of this, as opposed to simply using the clear() method of ArrayLists.
is using the new command to clear a list is ok and is it faster than clearing a list ?
i am using java version 1.6
Do note that clearing and re-instantiating a list is not the same thing!
Consider this example:
a = new ArrayList();
a.add("Hello")
b = a;
a = new ArrayList(); // a is now empty while b contains hello!
Versus
a = new ArrayList();
a.add("Hello")
b = a;
a.clear(); // Both a and b are now empty.
If the side-effects (shared references) are not an issue, then it is just two ways of clearing a list. It should probably not be a performance issue unless this is called millions of times.
No, they don't do the same thing. The method clear() clears an existing list - anything which still has a reference to the list and looks at it later will see that it's empty.
The approach with the new keyword, changes the value of the list variable but does nothing to the existing ArrayList object - so if anything else has a reference to the same object, they won't see any changes.
If the list is used elsewhere calling clear() might cause side effects.
However, if that is not the case, I'd say that creating a new list instead of clearing the old one might be faster (however, probably for huge lists only, since ArrayList's clear() just iterates over the elements and set's them as null), but most likely it's just a matter of programming style.
Wether it is the same or not it depends on what uselist(...) does internally with the list.
For example, suppose you have the following code in uselist :
public void uselist(List l) {
this.mylist = l;
}
In that case, your code will create a new list and not touch this.mylist . If instead you call .clear() on it, you are clearing that same list.
The difference can be fatal and hard to see. For example hibernate will flip out of you use list = new ArrayList(); and then try to update the list in the db but it works just fine with clear() as hibernate then can see the connection.
clear() // operates on your old object
list = new ArrayList(); // list will be a new object the old will be GCed

Categories