Как я могу проверить, отличаются ли два ArrayList, мне все равно, что изменилось
Как проверить, отличаются ли два ArrayLists друг от друга? Меня не волнует, в чем разница, я просто хочу знать, если они не совпадают.
Я собираю список баллов из базы данных каждую минуту, и только если список баллов, который я набрал, отличается от того, который я набрал минуту назад, я хочу отправить его клиенту.
Теперь значение ArrayList является фактически классом, который я создал (который содержит имя, lvl, rank, score).
Мне нужно реализовать equals()
на нем?
Ответы
Ответ 1
Здесь простой метод, который проверяет, содержит ли 2 списка массивов одинаковые значения независимо от их порядка.
//the name of the method explains it well...
public boolean isTwoArrayListsWithSameValues(ArrayList<Object> list1, ArrayList<Object> list2)
{
//null checking
if(list1==null && list2==null)
return true;
if((list1 == null && list2 != null) || (list1 != null && list2 == null))
return false;
if(list1.size()!=list2.size())
return false;
for(Object itemList1: list1)
{
if(!list2.contains(itemList1))
return false;
}
return true;
}
Ответ 2
По определению "идентичность"
Как отметил Йоахим, для большинства приложений List.equals(Object o)
работает:
Сравнивает указанный объект с этим списком для равенства. Возвращает true
тогда и только тогда, когда указанный объект также является списком, оба списка имеют одинаковый размер, и все соответствующие пары элементов в двух списках равны. (Два элемента e1
и e2
равны, если (e1==null ? e2==null : e1.equals(e2))
.) Другими словами, два списка определены равными, если они содержат одни и те же элементы в одном порядке. Это определение гарантирует, что метод equals
корректно работает в разных реализациях интерфейса List
.
В зависимости от того, как вы его используете, это может работать не так, как ожидалось. Например, если у вас есть List<int[]>
, он не работает, потому что массивы наследуют equals
из Object
, который определяет равенство как ссылочный идентификатор.
List<int[]> list1 = Arrays.asList(new int[] { 1, 2, 3 });
List<int[]> list2 = Arrays.asList(new int[] { 1, 2, 3 });
System.out.println(list1.equals(list2)); // prints "false"
Кроме того, два списка с разными параметрами типа могут быть equals
:
List<Number> list1 = new ArrayList<Number>();
List<String> list2 = new ArrayList<String>();
System.out.println(list1.equals(list2)); // prints "true"
Вы также упомянули, что список должен содержать элементы одного типа. Здесь еще один пример, когда элементы не имеют одного и того же типа, но все же они equals
:
List<Object> list1 = new ArrayList<Object>();
List<Object> list2 = new ArrayList<Object>();
list1.add(new ArrayList<Integer>());
list2.add(new LinkedList<String>());
System.out.println(list1.equals(list2)); // prints "true"
Итак, если вы не четко определите, что означает для вас равенство, вопрос может иметь очень разные ответы. Для большинства практических целей достаточно List.equals
.
При реализации equals
Информация после обновления подсказывает, что List.equals
будет выполнять задание просто отлично, при условии, что элементы будут правильно реализовывать equals
(потому что List<E>.equals
вызывает E.equals
в не-t221 > -элементах, по документации API выше).
Итак, в этом случае, если у нас есть, скажем, List<Player>
, то Player
должен @Override equals(Object o)
возвращать true
, если o instanceof Player
и в соответствующих полях, все они equals
( для ссылочных типов) или ==
(для примитивов).
Конечно, когда вы @Override equals
, вы также должны @Override int hashCode()
. Едкий приемлемый минимум - return 42;
; немного лучше - return name.hashCode();
; лучше всего использовать формулу, которая включает все поля, на которых вы определяете equals
. Хорошая среда IDE может автоматически генерировать методы equals/hashCode
для вас.
См. также
- Эффективное Java 2nd Edition
- Пункт 8: соблюдать общий контракт при переопределении равных
- Пункт 9: Всегда переопределять хэш-код при переопределении равных
Ссылки API
Связанные вопросы
Вкл equals/hashCode
комбо:
Вкл equals
vs ==
:
Ответ 3
Используйте equals()
. Пока элементы внутри списков реализуют equals()
правильно, он вернет правильные значения.
Если вы не хотите игнорировать порядок значений, вы должны сбросить значения в двух объектах Set
и сравнить их с помощью equals()
.
Ответ 4
Как сказал в своем ответе @Joachim Sauer, равные должны работать, если списки равны, а их содержимое реализовано правильно. Но он не должен работать, если элементы не находятся в одном "порядке", так как он не используется для проверки. В этом смысле он проверяет "строгое" равенство, как указано @jarnbjo
//From android Arraylist implementation
Iterator<?> it = that.iterator();
for (int i = 0; i < s; i++) {
Object eThis = a[i];
Object eThat = it.next();
if (eThis == null ? eThat != null : !eThis.equals(eThat)) {
return false;
}
}
Однако мне хотелось немного по-другому, мне не нравился порядок или что-то в этом роде. Все, что я хотел, было убедиться, что у двух не было одинаковых предметов.
Мое решение,
//first check that both are not null and are of same length. (not shown here)
//if both match, pull out the big guns as below
...
List<Object> comparedList = new ArrayList<>(listOne);
comparedList.removeAll(listTwo);
if(comparedList.size() != 0) //there are differences between the two
Это менее результативно, так как он дважды повторяется, сначала в removeAll
, а затем в contains
, который вызывается removeAll
.
Мой список был гарантированно коротким, поэтому я не против удара.
Ответ 5
Вы также можете проверить Arraylist, как показано ниже:
public boolean equalLists(List<String> one, List<String> two){
if (one == null && two == null){
return true;
}
if((one == null && two != null)
|| one != null && two == null
|| one.size() != two.size()){
return false;
}
//to avoid messing the order of the lists we will use a copy
//as noted in comments by A. R. S.
one = new ArrayList<String>(one);
two = new ArrayList<String>(two);
Collections.sort(one);
Collections.sort(two);
return one.equals(two);
}
Благодаря @Jacob