Reputation: 29
I am trying to use the set as a buffer to hold some values, store them in the map, and then reset itself to prepare for the next stream of data. Here is some relevant code :
Map<Set<String>, Integer> map = new LinkedHashMap<Set<String>, Integer>();
Set<String> set = new LinkedHashSet<String>();
set.add("A");
map.put(set, 1);
for (Set<String> entry : map.keySet()) {
for (String word : entry) {
System.out.println("BEFORE CLEAR - "+word);
}
}
set.clear();
for (Set<String> entry : map.keySet()) {
System.out.println("AFTER CLEAR - "+entry.size());
for (String word : entry) {
System.out.println("AFTER CLEAR - "+word);
}
}
The output I get is :
BEFORE CLEAR - A
AFTER CLEAR - 0
If I change the set.clear()
to set = null
, then output is :
BEFORE CLEAR - A
AFTER CLEAR - 1
AFTER CLEAR - A
This implies when I clear data in set AFTER putting it into map, map does not receive a new copy - and that's why on clearing the set, the copy in map is also being cleared. I am kind of surprised by the behavior because as Java developers we are pushed towards using immutable copies, which seems to be violated here. Am I misunderstanding something ?
My question is that is there a better solution to this problem ? It works on setting set to null, which I have to re-initalize everytime with a new LinkedHashSet() in a while loop. And this looks bad to me.
EDIT : I have no problems setting set to null, I certainly want that data in the map. I only have a problem with creating new objects of set, rather than using the same one.
Upvotes: 0
Views: 258
Reputation: 1755
If you make set = null
you will erase a local reference to a set, but your map will still hold a reference to set object. To remove set from map you need to map.remove(set)
Java is not doing a deep set copy while passing it as a parameter, the only copied thing is a reference to object. If you want your set to hold all data then just not clear it - create new set when you need another empty one. Think about object in java like about occupied piece of memory, when you write something like
Set<String> set = new LinkedHashSet<String>();
the first part Set<String> set
is a reference (something like pointer in C) to that piece of memory, the second part new LinkedHashSet<String>();
is actually allocation these piece of memory. If you clear stuff in that piece of memory (set.clear()) you will erase stuff written there. If you need new piece of memory to write new data without erasing old one you need to call new LinkedHashSet<String>();
again.
Upvotes: 2
Reputation: 9628
First, you're right, and that's a hassle sometime but Collections
in Java are indeed mutable.
Second, I think that you actually need to copy the content of your Set
to put that content into your Map
, instead of putting the reference to that Set
, if you want to clear it later. Thus, I would suggest you to simply replace:
map.put(set, 1);
by:
map.put(new HashSet<>(set), 1);
In my opinion, it makes perfect sense, because:
Set
Set
to fulfill the role of the first one, you can re-use it as your intended to.Upvotes: 0