Maybe my logic stopped working for a bit, but I find this behavior confusing. Suppose I have a TreeMap as follows:
TreeMap<Integer, Double> map = new TreeMap<Integer, Double>(Collections.reverseOrder());
map.put(123, 0.5);
map.put(678, 1.0);
map.put(567, 0.1);
int key = 100;
Now, I want to use the map.lowerEntry(key)
and according to the documentation of the getter:
Returns a key-value mapping associated with the greatest key strictly less than the given key, or null if there is no such key.
I would expect null
as a result, but the system call System.out.println("Lower than "+key+ " is "+map.lowerEntry(key));
produces Lower than 100 is 123=0.5
. If I use map.higherEntry(key)
which is documented as
Returns a key-value mapping associated with the least key strictly greater than the given key, or null if there is no such key.
then I get the desired result, but it is counter-intuitive based on the documentation. I guess calling the Collections.reverseOrder()
comparator on the TreeMap inverts the logic applied inside the map?
EDIT
Using a TreeSet I get consistent behavior (regarding the function names) when it is initialized with the Collections.reverseOrder()
comparator:
TreeSet<Integer> set = new TreeSet<Integer>(Collections.reverseOrder());
set.add(123);
set.add(678);
set.add(567);
int key = 200;
System.out.println("Lower than "+key+ " is "+set.tailSet(key));
produces Lower than 200 is [123]
which I would expect.
Is this inconsistency between TreeMap and TreeSet normal? Can someone please explain please? Thank you.
I'll try and "summarize" the comments above for some structure:
TreeMap.lowerEntry(key)
andTreeSet.headSet(key)
have basically the same behavior which is they return the elements which are lower than the key. The same holds forTreeMap.higherEntry(key)
andTreeSet.tailSet(key)
.Using a reverse comparator on either of them would cause the order to be reversed, i.e. higher becomes lower and lower becomes higher. This might seem counterintuitive when the keys/elements are numbers etc. but so would be reversing their sort order.
If you add some semantics to the elements it might be easier to understand:
Let's say we're dealing with a ticketing system that counts the occurence of errors while some person defines priorities for the errors to be fixed.
Now you want to iterate through that list of errors and display them, so you sort them using a
TreeMap<Integer, ErrorDescription>
.Depending on the semantics of the key you'd use a different comparator:
Last, a quote from your last comment:
If you consider the example above just adding semantics to numbers would change the meaning of "lower" and "higher". Additionally take into account that numeric keys are just one type of keys, you could also use dates, strings, enums or a multitude of other objects which have a natural order (thus implementing
Comparable
) or need to be ordered on a case-by-case basis (thus using aComparator
).Because there are so many different situations the documentation has to apply to it's hard to write it in a way that fits everything. The meaning of "lower" and "higher" depends on the situation anyway and thus it's easiest to just use that wording and leave the interpretation of the semantics to the developer.