Search code examples
javasetequalitycomparatortreeset

Java Comparator in Sets with equal items


Normally in a TreeSet there shouldn't be two equal items. But in reality there are often situations where you want to maintain kind of a sorted List instead of a Set. Still there is afaik no TreeList or any SortedList in Java. Though you can of course use Collections.sort().

My question is: what is the proper way to use a TreeSet (or any sorted set) so that it is also capable of containing equal items?

I normally do something like that:

new Comparator<MyObject>() {
    @Override
    public int compare(MyObject o1, MyObject o2) {
        int result = Float.compare(o1.getDistance(), o2.getDistance());
        
        //both distances are equal so we use the object hash as distinctive
        //property.
        if (result == 0) {
            result = Integer.compare(System.identityHashCode(o1), 
                System.identityHashCode(o2))
        }
        return result;
    }
}

While this works very well, this has of course the disadvantage that there is still the slim chance of a hash collision, that would lead to missing objects in the TreeSet.

So I wonder if there is any better way to really distinguish these objects properly?


Solution

  • I have been using

    import com.google.common.collect.TreeMultiset;
    

    effortless and successfully.

    You shouldn't try to use workarounds when good libraries are around.

    There may be other libs as well, of course.

    Later

    I should have raised a red flag at "equal" in combination with "set". This is a no-no. You can have equal multiple equal keys in a Map.

    If you want to store objects repeatedly, even if they are equal, use a List; it's up to you to decide whether an equal element should be added or not.

    Another thought:

    Maybe you want an IdentityHashMap which uses reference equality rather than equals.

    BUT be prepared for endless difficulties if you violate the hashCode/equals contract in your class.