Comment puis-je vérifier si deux ArrayLists diffèrent l'une de l'autre? Je me fiche de la différence, je veux juste savoir si ce n'est pas pareil.
Je récupère la liste des scores dans une base de données toutes les minutes, et seulement si la liste des scores que j'ai récupérée est différente de celle que j'ai récupérée il y a une minute, je veux l'envoyer au client.
Maintenant, la valeur de ArrayList est en fait une classe que j'ai créée (qui contient le nom, le niveau, le rang, le score).
Dois-je implémenter equals()
dessus?
Voici une méthode simple qui vérifie si 2 listes de tableaux contiennent les mêmes valeurs quel que soit leur ordre.
//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;
}
Comme Joachim l'a noté, pour la plupart des applications, la définition List.equals(Object o)
fonctionne:
Compare l'objet spécifié avec cette liste pour l'égalité. Renvoie
true
si et seulement si l'objet spécifié est également une liste, les deux listes ont la même taille et toutes les paires d'éléments correspondantes dans les deux listes sont égales. (Deux élémentse1
Ete2
Sont égaux si(e1==null ? e2==null : e1.equals(e2))
.) En d'autres termes, deux listes sont définies pour être égales si elles contiennent les mêmes éléments dans le même ordre. Cette définition garantit que la méthodeequals
fonctionne correctement sur différentes implémentations de l'interfaceList
.
Selon la façon dont vous l'utilisez, cependant, cela peut ne pas fonctionner comme prévu. Si vous avez un List<int[]>
, Par exemple, cela ne fonctionne pas vraiment parce que les tableaux héritent equals
de Object
qui définit l'égalité comme identité de référence.
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"
De plus, deux listes avec un paramètre de type différent peuvent être equals
:
List<Number> list1 = new ArrayList<Number>();
List<String> list2 = new ArrayList<String>();
System.out.println(list1.equals(list2)); // prints "true"
Vous avez également mentionné que la liste doit contenir des éléments du même type. Voici encore un autre exemple où les éléments n'ont pas le même type, et pourtant ils sont 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"
Donc, à moins que vous ne définissiez clairement ce que l'égalité signifie pour vous, la question peut avoir des réponses très différentes. Cependant, pour la plupart des applications pratiques, List.equals
Devrait suffire.
equals
Les informations après la mise à jour suggèrent que List.equals
Fera très bien le travail, à condition que les éléments implémentent equals
correctement (car List<E>.equals
Invoque E.equals
Sur les éléments nonnull
-, selon la documentation de l'API ci-dessus).
Donc dans ce cas, si nous avons, disons, un List<Player>
, Alors Player
doit @Override equals(Object o)
pour retourner true
si o instanceof Player
Et dans les champs appropriés, ils sont tous equals
(pour les types de référence) ou ==
(pour les primitives).
Bien sûr, lorsque vous @Override equals
, Vous devez également @Override int hashCode()
. Le minimum à peine acceptable est de return 42;
; un peu mieux est de return name.hashCode();
; le mieux est d'utiliser une formule qui implique tous les champs sur lesquels vous définissez equals
. Un bon IDE peut générer automatiquement des méthodes equals/hashCode
Pour vous.
Object.equals(Object)
Object.hashCode()
Java.lang.Comparable
- pas nécessaire ici, mais un autre contrat API important JavaSur le combo equals/hashCode
:
Sur equals
vs ==
:
Utilisez equals()
. Tant que les éléments à l'intérieur des listes implémentent correctement equals()
, ils renverront les valeurs correctes.
À moins que vous ne vouliez ignorer l'ordre des valeurs, vous devez alors vider les valeurs dans deux objets Set
et les comparer à l'aide de equals()
.
Comme @Joachim Sauer l'a mentionné dans sa réponse, equals devrait fonctionner si les listes sont égales et que leur contenu est correctement implémenté. Mais, cela ne devrait pas fonctionner si les éléments ne sont pas dans le même "ordre" car il n'utilise pas de contenu pour la vérification. En ce sens, il vérifie l'égalité "stricte" comme mentionné par @jarnbjo
//From Android's 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;
}
}
Cependant, je voulais un comportement quelque peu différent, je me fichais de l'ordre ou de quelque chose comme ça. Tout ce que je voulais, c'était être sûr que les deux ne contenaient pas les mêmes éléments. Ma solution,
//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
C'est moins performant car il boucle deux fois, d'abord dans removeAll
puis dans contains
qui est appelé par removeAll
.
Ma liste était garantie d'être courte, donc cela ne me dérangeait pas.
Vous pouvez les convertir en chaîne, puis comparer comme
list1.toString().equals(list2.toString())