The professional, friendly Java community. 21,500 members and growing!

The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.

TreeSet contains(obj) doe not behave as expected

Hello,

I am using the class TreeSet from the java collections library and I have a little problem with the "contains(Object)" method.
I want to use the TreeSet to order a number of Layer-Objects by their Z-Coordinate in a little project of mine.
Sometimes the Z-Coordinate of a layer can change, in that case I
1). remove it from the set
2). change its Z-value
3). add it to the set again
However, my problem is that sometimes a Layer that was added to the set can not be removed anymore since the set doesnt notice, that the Layer is contained within the set.

Re: TreeSet contains(obj) doe not behave as expected

You say it happens "sometimes." There must be something special about those times contributing to the behavior. See if you can define what's special about those cases, using prints and comparisons liberally or a debugger.

Here's an SSCCE that cobbles together the code you've posted into something that runs and then tests the scenario you described. All seems to work as advertised. You are welcome to manipulate the example as needed to show the behavior you're experiencing.

Re: TreeSet contains(obj) doe not behave as expected

It happens when I change the Z-coordinate of a layer. I remove it, change the Z, and add it again.
Its not arbitrary, it always happens with a given set of layers and always happens to the same layer.
I add 2 layers with Z = 0, and then 2 layers with Z = 1. Then I pick the first layer with Z == 0 and I want to change its Z value to 2 but the error occurs.

Re: TreeSet contains(obj) doe not behave as expected

See the API for TreeSet

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal.

If all you want is to order the Layers, I'd add them to a List then use Collections.sort to sort the List - a Set should only be used when you want unique elements based upon their equals method - while its tough to tell here this doesn't look to be the case. If you want uniques based upon the z value, then override the hashCode/equals methods to define equality based upon the z value.

Re: TreeSet contains(obj) doe not behave as expected

Well, the comparator returns 0 if 2 elements are equal. As far as I understood thats how its supposed to be, isnt it?

What exactly would be a good choice for a quick sorted data structure? I thought a binary tree (which the treeSet is, isnt it?) would be a good idea.

Again I suggest to read the API, as I would say this is a mis-use of a TreeSet (unless I misunderstand the goal at hand). A Set should be used if you want unique elements (based upon the equals/hashCode and in the case of a TreeSet the compareTo/compare methods), which (correct me if I'm wrong) does not seem to be what you are trying to accomplish. It seems to me you just want a way to Sort, which is why other tools such as Collections.sort() or Arrays.sort() exists: to sort other data structures.

Re: TreeSet contains(obj) doe not behave as expected

But wouldnt a tree be faster?

Every time you add to a Tree set it takes log(n) time, so to add everthing is n*log(n), the same as Collections.sort takes (the additions to the end of a List in theory take constant time O(1) depending upon the context). Every addition to the TreeSet takes log(n), as opposed to every addition to a List takes constant (or possible linear depending upon context) time. If every addition is crucial time-wise then using a List may be more appropriate.

By the way, where am I adding the same element twice to the TreeSet in my example? Every element should only be inserted once by my intention.

That's the problem. Consider how things are being organized: a self-balancing tree. Suppose you add 1, 2, 3, and 4 (numbers represent your layers, not numerals) and for the sake of argument consider the tree balance as follows:

3
/ \
2 4
\
1

When you try to remove 1, it does a comparison against 2, the comparator returns the number 1, so the algorithm starts down the branch of 4. Unable to find 1 it doesn't remove it.

To correctly implement the TreeSet, your comparator should not return 1 for equal z values (and you should implement the equals/hashCode methods)

Re: TreeSet contains(obj) doe not behave as expected

But it says the comparator should only return 0 if both elements are equal. In my case the equal Z correlates to a "dont care" in what way they are ordered. After all, my comparator correctly returns 0 if both elements are equal.
At best the documentation is slightly confusing.

But I already have switched to an array list. your argument about the speed is very good though.

Re: TreeSet contains(obj) doe not behave as expected

But I already have switched to an array list. your argument about the speed is very good though.

Glad you got it working. Actually, I feel my argument about the way the tree can be organized and why you are encountering your issue was pretty descent as well

Originally Posted by Cornix

But it says the comparator should only return 0 if both elements are equal. In my case the equal Z correlates to a "dont care" in what way they are ordered. After all, my comparator correctly returns 0 if both elements are equal.
At best the documentation is slightly confusing.

Don't mean to belabor the point, but "Don't care" is the problem. In this context, a sorting data structure not meant for duplicate values used to sort on values that have duplicates can run into problems when you try to do such a thing.