Comparator and equals()

后端 未结 11 2002
终归单人心
终归单人心 2020-12-16 17:27

Suppose I need TreeSet with elements sorted with some domain logic. By this logic it doesn\'t matter order of some elements that doesn\'t equal so compare metho

11条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-16 17:54

    While this might work, it is far from being a best practice.

    From the SortedSet docs:

    Note that the ordering maintained by a sorted set (whether or not an explicit comparator is provided) must be consistent with equals if the sorted set is to correctly implement the Set interface. (See the Comparable interface or Comparator interface 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 sorted set 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 sorted set, equal. The behavior of a sorted set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.

    For objects that implement Comparable, there should always be a consistency between the methods equals(), hashcode() and compareTo().


    I'm afraid a SortedSet is just not what you want, nor will a Guava MultiSet be adequate (because it will not let you independently retrieve multiple equal items). I think what you need is a SortedList. There is no such beast that I know of (maybe in commons-collections, but those are a bit on the legacy side), so I implemented one for you using Guava's ForwardingList as a base class. In short: this List delegates almost everything to an ArrayList it uses internally, but it uses Collections.binarySearch() in it's add() method to find the right insertion position and it throws an UnsupportedOperationException on all optional methods of the List and ListIterator interfaces that add or set values at a given position.

    The Constructors are identical to those of ArrayList, but for each of them there is also a second version with a custom Comparator. If you don't use a custom Comparator, your list elements need to implement Comparable or RuntimeExceptions will occur during sorting.

    public class SortedArrayList extends ForwardingList implements
        RandomAccess{
    
        private final class ListIteratorImpl extends ForwardingListIterator{
            private final int start;
            public ListIteratorImpl(final int start){
                this.start = start;
            }
    
            @Override
            public void set(E element){throw new UnsupportedOperationException();}
    
            @Override
            public void add(E element){throw new UnsupportedOperationException();}
    
            @Override
            protected ListIterator delegate(){return inner.listIterator(start);};
    
        }
    
        private Comparator comparator;
    
        private List inner;
    
        public SortedArrayList(){this(null, null, null);}
    
        @SuppressWarnings("unchecked")
        private SortedArrayList(
            final List existing,
            final Collection values,
            final Comparator comparator
        ){
            this.comparator =
                (Comparator)
                   (comparator == null
                       ? Ordering.natural()
                       : comparator   );
            inner = (
                existing == null
                    ? (values == null
                          ? new ArrayList(values)
                          : new ArrayList()
                       )
                    : existing;
        }
    
        public SortedArrayList(final Collection c){
            this(null, c, null);
        }
    
        public SortedArrayList(final Collection c,
            final Comparator comparator){
            this(null, c, comparator);
        }
    
        public SortedArrayList(final Comparator comparator){
            this(null, null, comparator);
        }
    
        public SortedArrayList(final int initialCapacity){
            this(new ArrayList(initialCapacity), null, null);
        }
    
        public SortedArrayList(final int initialCapacity,
            final Comparator comparator){
            this(new ArrayList(initialCapacity), null, comparator);
        }
    
        @Override
        public boolean add(final E e){
            inner.add(
                Math.abs(
                    Collections.binarySearch(inner, e, comparator)
                ) + 1,
                e
            );
            return true;
        }
    
        @Override
        public void add(int i, E e){throw new UnsupportedOperationException();}
    
        @Override
        public boolean addAll(final Collection collection){
            return standardAddAll(collection);
        }
    
        @Override
        public boolean addAll(int i,
            Collection es){
            throw new UnsupportedOperationException();
        }
    
        @Override
        protected List delegate(){ return inner; }
    
        @Override
        public List subList(final int fromIndex, final int toIndex){
            return new SortedArrayList(
                inner.subList(fromIndex, toIndex),
                null,
                comparator
            );
        }
    
        @Override
        public ListIterator listIterator(){ return new ListIteratorImpl(0); }
    
        @Override
        public ListIterator listIterator(final int index){
            return new ListIteratorImpl(index);
        }
    
        @Override
        public E set(int i, E e){ throw new UnsupportedOperationException(); }
    
    }
    

提交回复
热议问题