Reputation: 4471
I have an issue when using removeAll()
, some objects can't be removed properly.
data class Dog(var name: String)
val dog1 = Dog(name = "dodo")
val dog2 = Dog(name = "mimi")
val set = mutableSetOf<Dog>()
set.add(dog1)
set.add(dog2)
dog1.name = "dodo2"
val beforeSize = set.size // 2
set.removeAll { true }
val afterSize = set.size // why it is 1!?, I expect it should be 0
The removeAll
didn't work as I expected. There is still one element in the mutable set. Any idea?
Upvotes: 9
Views: 2749
Reputation: 200148
Javadoc of Set
:
Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set.
By writing
dog1.name = "dodo2"
you did exactly that, you changed the object in a way that affects equals
comparisons. Specifically, by using the construct
set.removeAll { true }
you exercised a code path in LinkedHashSet
that visits each element, tests the predicate on it, and then tries to remove it as if by calling set.remove(it)
. This will cause it
to recalculate its hash code, now different from what it was when you inserted it into the set. LinkedHashSet
will then look up the corresponding hash bucket and fail to find it
there.
Upvotes: 13
Reputation: 81879
You're changing the object after it has been added to the set. That should be avoided
You can use clear
instead:
set.clear()
Or move the mutation of your object:
val dog1 = Dog(name = "dodo")
val dog2 = Dog(name = "mimi")
dog1.name = "dodo2"
val set = mutableSetOf(dog1, dog2)
Upvotes: 2