TreeSet равен другому TreeSet - PullRequest
       19

TreeSet равен другому TreeSet

0 голосов
/ 08 февраля 2019

Как узнать, равны ли два объекта TreeSet?Я использую open-jdk-10 .

ModifiebleObject

class ModifiebleObject implements Comparable<ModifiebleObject>{

    Integer number;
    String text;

    @Override
    public int compareTo(final ModifiebleObject o) {
        return this.number - o.number;
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) return true;
        if (!(o instanceof ModifiebleObject)) return false;
        final ModifiebleObject that = (ModifiebleObject) o;
        return Objects.equals(number, that.number) &&
                Objects.equals(text, that.text);
    }

    @Override
    public int hashCode() {
        return Objects.hash(number, text);
    }
}

SomeCode

SortedSet<ModifiebleObject> tree1 = prepare();
SortedSet<ModifiebleObject> tree2 = prepare(); //Returns cloned elements, so object references in tree1 and tree2 are different.

// ModifiebleObject implements Comparable<ModifiebleObject>
// compareTo does not use all the fields, just some of them.
//setSomeValueOutsideOfComparable sets value of the field, which is not used by compareTo
tree2.first().setSomeValueOutsideOfComparable("newValue");

boolean tree1EqualsTree2 = tree1.equals(tree2); //Returns true

Поскольку

TreeSet вызывает AbstractSet.containsAll -> TreeSet.contains -> TreeMap.containsKey -> TreeMap.getEntry != null

TreeMap.getEntry использует compactor или elements CompareTo (элементы реализуют Comparable).

Забавно, но JavaDoc лжет!

java.utilTreeSet

/**
 * Returns {@code true} if this set contains the specified element.
 * More formally, returns {@code true} if and only if this set
 * contains an element {@code e} such that
 * {@code Objects.equals(o, e)}.
 *
 * @param o object to be checked for containment in this set
 * @return {@code true} if this set contains the specified element
 * @throws ClassCastException if the specified object cannot be compared
 *         with the elements currently in the set
 * @throws NullPointerException if the specified element is null
 *         and this set uses natural ordering, or its comparator
 *         does not permit null elements
 */
public boolean contains(Object o) {
    return m.containsKey(o);
}

Более формально, возвращает {@code true} если и толькоесли этот набор содержит элемент {@code e} такой, что {@code Objects.equals (o, e)}.

Но в действительности он использует compareTo.


Обновление

Какая другая коллекция из jdk или другой библиотеки, которую я мог бы использовать, которая гарантирует уникальные элементы и отсортирована, и эквивалентна другой коллекции, используемой для каждого элемента, равна.

Ответы [ 3 ]

0 голосов
/ 08 февраля 2019

Если у вас есть Set of Defined Object, вы можете переопределить хэш-код и метод equals и метод сравнения ниже, основанный на хэш-коде и методе equals.Вы можете использовать

 org.apache.commons.collections
 SetUtils.isEqualSet(set1, set2);

или

 org.apache.commons.collections
 CollectionUtils.isEqualCollection(a, b)
0 голосов
/ 12 февраля 2019

Это решение, которое сработало для меня.

class TreeSetWithEquals extends TreeSet {

    //Constructors which I will use
    //

    // I consider two sets equal if they have equal elements in the same order!
    @Override
    public boolean equals(Object o) {
        //Check if Object not null, not the same reference as this, and 
        // it is instance of Set
        //And their sizes are equal
        //Iterate through boths sets and apply equals for each method.
    }
}

Зачем мне это делать?Ну, в нашем коде мы генерируем равные для других объектов в Idea ->, которая использует Objects.equals(this.field_i, that.field_i).Нам лень искать в нашем коде места и заменять Objects.equals(this.field_i, that.field_i), если field_i - отсортированный набор в класс util, чтобы проверить равенство наборов.Поэтому проще использовать набор, который поддерживает сортировку, но использует eqauls для каждого элемента внутри this.equals.

Некоторые люди говорят мне, что eqauls, hashCode, compareTo должны быть непротиворечивыми,Я согласен с eqauls, hashCode должен быть последовательным.

Например.

enum WeaponType {

     KNIFE,
     HAND_GUN,
     TWO_HANDED_GUN,
     GRANADES, //To allow flash, smoke and fragmentation granades
     DEFUSE_KIT
}

class Shooter {

    // make sure we can have different weapons,
    // but only one of type is allowed.
    // Our tree set with such comparator will guarantee this requirement.
    private SortedSet<Weapon> weapons = buyWeapons(andUseWeaponTypeComparator);

Для этого я определю WeaponComparator

Comparator<Weapon> WEAPON_COMPARATOR = Compareator
       .comparing(Weapon::getType, Comparator.naturalOrder()) //enum uses its element order.
}

Теперь, если вы хотите сохранить стрелка иотправлять сообщения в кафке на другие микро-сервисы, у вас будет equals, который проверяет сущности who Shooter .

0 голосов
/ 08 февраля 2019

JavaDoc для TreeSet прямо говорит об этом.Это не какой-то заговор.

Обратите внимание, что порядок, поддерживаемый набором (независимо от того, предоставляется ли явный компаратор) должен соответствовать равным , если он предназначен для правильной реализацииУстановить интерфейс.(См. Comparable или Comparator для точного определения соответствия с equals.) Это так, потому что интерфейс Set определен в терминах операции equals, , но экземпляр TreeSet выполняет все сравнения элементов, используя его CompareTo (илисравните), поэтому два элемента, которые считаются равными этим методом, с точки зрения множества равны.Поведение множества корректно определено, даже если его порядок не совпадает с равенством;он просто не соблюдает общий контракт интерфейса Set.

Ваш класс проигнорировал совет Comparable, и вы платите за него.

Настоятельно рекомендуется, но не обязательно, чтобы (x.compareTo(y)==0) == (x.equals(y))

...