Проблема с реализацией removeAll для списка пользовательских объектов - PullRequest
6 голосов
/ 11 апреля 2010

В моем коде есть сценарий, в котором мне нужно сравнить два списка и удалить из первого списка объекты, которые присутствуют во втором списке. Сродни тому, как работает объект «removeAll» для List. Поскольку мой список создан на пользовательском объекте, метод removeAll не будет работать для меня.

Я пробовал различные методы, чтобы сделать эту работу: - реализовал equals () и hashCode для пользовательского объекта, включающего список - реализован Comparable Interface для пользовательского объекта - реализован интерфейс Comparator для пользовательского объекта

Я даже пытался использовать методы Apache Common CollectionUtils и ListUtils (вычитать, пересекать, удалять все). Кажется, никто не работает.

Я понимаю, что, возможно, мне понадобится написать собственный код удаления. Но не уверен, как это сделать. Будем очень благодарны за любые указатели, помогающие мне двигаться в правильном направлении.

Спасибо, Jay

Ответы [ 4 ]

14 голосов
/ 11 апреля 2010

Коллекции Java уже обслуживают ваш сценарий. Вызовите Collection.removeAll(Collection), и он удалит все элементы из переданной коллекции, используя метод equals() для проверки на равенство.

List<String> list1 = new ArrayList<String>();
Collections.addAll(list1, "one", "two", "three", "four");
List<String> list2 = new ArrayList<String>();
Collections.addAll(list2, "three", "four", "five");
list1.removeAll(list2); // now contains "one", "two"

Для того, чтобы эта работа работала с объектами, которые вы храните, необходимо правильно реализовать контракт equals / hashCode, а именно: с учетом любых двух объектов a и b:

a.equals(b) == b.equals(a)

и

a.hashCode() == b.hashCode() if a.equals(b)

Неправильно определенные методы equals и hashCode создают неопределенное поведение и являются частой причиной проблем, связанных с коллекциями.

6 голосов
/ 11 апреля 2010

Переопределение методов equals и hashCode достаточно, чтобы метод removeAll работал с пользовательскими объектами.

Вполне вероятно, что вы не изменили их должным образом. Некоторый код нам очень поможет.

4 голосов
/ 11 апреля 2010

Вы сказали:

... Так как мой список создан на пользовательском объекте, метод removeAll не будет работать для меня.

Как уже говорили другие, .removeAll () должен работать для сценария, который вы описали, даже для пользовательских объектов, если пользовательские объекты подчиняются контрактам, которые Java Collections ожидает от своих объектов, включая должную реализацию equals () и Метод hashCode ().

Я пробовал различные методы, чтобы сделать эту работу: - реализовал equals () и hashCode для пользовательского объекта, составляющего список - реализовал Comparable Interface для пользовательского объекта - реализовал интерфейс Comparator для пользовательского объекта ...

Звучит так, как будто вы стреляете из разных подходов: кодируете один, пробуете его, быстро кодируете другой, пробуете его, кодируете еще один, ... Стоит замедлить ход и попытаться понять, почему каждый подход потерпел неудачу и / или определите, почему этот подход не будет работать в вашей ситуации, прежде чем переходить к следующей. Если вы уже исследовали и определили, почему каждый подход не будет работать, пожалуйста, объясните в своем вопросе. Если вы этого не сделали, сообщите нам об этом, отправив код.

Поскольку большинство людей согласны с тем, что первый подход (.removeall ()) должен работать, и поскольку в него вовлечены пользовательские объекты, почему бы не сделать быстрый обзор этого вопроса StackOverflow, чтобы увидеть, выпрыгивает ли что-нибудь из вас:

Переопределение equals и hashCode в Java

"Какие проблемы / ловушки мне нужно учитывать при переопределении equals и hashCode в классе java?"

0 голосов
/ 13 октября 2013

Я обнаружил, что его первоначальное утверждение верно. removeAll работает автоматически, только если вы переопределите удаление в итераторе. Недостаточно просто переопределить удаление в коллекции, так как все removeAll (и clear, и retainAll) используют итератор для работы. Поскольку вам не следует изменять базовую коллекцию при использовании итератора, за исключением удаления в итераторе, если вы не переопределите удаление в итераторе, removeAll, clear и retainAll не будут работать. Если вы бросите исключение UnsupportedOperationException в методе удаления внутри итератора, это то, что вы увидите, если вызовете один из трех обсуждаемых методов.

...