web-dev-qa-db-fra.com

Pourquoi les collections vides de types différents sont-elles égales?

Quel est le mécanisme ci-dessous qui rend différents types égaux?

import static org.testng.Assert.assertEquals;
@Test
public void whyThisIsEqual() {
    assertEquals(new HashSet<>(), new ArrayList<>());
}
52
Bartek

La assertEquals(Collection<?> actual, Collection<?> expected)documentation dit:

Affirme que deux collections contiennent les mêmes éléments dans le même ordre. Si ce n'est pas le cas, une erreur AssertionError est renvoyée.

Ainsi, le contenu des collections sera comparé. Si les deux collections sont vides, elles sont égales.

55
S.K.

Ils ne sont pas...

System.out.println(new HashSet<>().equals(new ArrayList<>())); // false

Ceci est spécifique à testngassertEquals

La documentation de cette méthode indique:

Affirme que deux collections contiennent les mêmes éléments dans le même ordre.

Et cela m'est ridicule, un Set n'a pas d'ordre en soi.

Set<String> set = new HashSet<>();
set.add("hello");
set.add("from");
set.add("jug");

System.out.println(set); // [from, hello, jug]

IntStream.range(0, 1000).mapToObj(x -> x + "").forEachOrdered(set::add);
IntStream.range(0, 1000).mapToObj(x -> x + "").forEachOrdered(set::remove);

System.out.println(set); // [jug, hello, from]

Donc, en les comparant à un Collection à à un moment donné , on obtiendrait des résultats intéressants.

Encore pire, Java-9Set::of Les méthodes implémentent une randomisation en interne, ainsi l'ordre (ou l'ordre) sera différent d'une exécution à l'autre.

31
Eugene

Testng appelle une méthode implémentée de cette façon.

  public static void assertEquals(Collection<?> actual, Collection<?> expected, String message) {
    if (actual == expected) {
      return;
    }

    if (actual == null || expected == null) {
      if (message != null) {
        fail(message);
      } else {
        fail("Collections not equal: expected: " + expected + " and actual: " + actual);
      }
    }

    assertEquals(
        actual.size(),
        expected.size(),
        (message == null ? "" : message + ": ") + "lists don't have the same size");

    Iterator<?> actIt = actual.iterator();
    Iterator<?> expIt = expected.iterator();
    int i = -1;
    while (actIt.hasNext() && expIt.hasNext()) {
      i++;
      Object e = expIt.next();
      Object a = actIt.next();
      String explanation = "Lists differ at element [" + i + "]: " + e + " != " + a;
      String errorMessage = message == null ? explanation : message + ": " + explanation;
      assertEqualsImpl(a, e, errorMessage);
    }
  }

Ceci essaye d'être utile mais est pauvre pour plusieurs raisons.

Deux collections égales peuvent sembler différentes.

Set<Integer> a = new HashSet<>();
a.add(82);
a.add(100);
System.err.println(a);
Set<Integer> b = new HashSet<>();
for (int i = 82; i <= 100; i++)
    b.add(i);
for (int i = 83; i <= 99; i++)
    b.remove(i);
System.err.println(b);
System.err.println("a.equals(b) && b.equals(a) is " + (a.equals(b) && b.equals(a)));
assertEquals(a, b, "a <=> b");

et

Set<Integer> a = new HashSet<>();
a.add(100);
a.add(82);
System.err.println(a);
Set<Integer> b = new HashSet<>(32);
b.add(100);
b.add(82);
System.err.println(b);
System.err.println("a.equals(b) && b.equals(a) is " + (a.equals(b) && b.equals(a)));
assertEquals(a, b, "a <=> b");

empreintes

[82, 100]
[100, 82]
a.equals(b) && b.equals(a) is true
Exception in thread "main" Java.lang.AssertionError: a <=> b: Lists differ at element [0]: 100 != 82
    at ....

Deux collections peuvent être identiques ou différentes selon la manière dont elles sont comparées.

assertEquals(a, (Iterable) b); // passes

assertEquals(a, (Object) b); // passes

assertEquals(Arrays.asList(a), Arrays.asList(b)); // passes
9
Peter Lawrey

Parce que pour la collection, seul le contenu est comparé, pas le type de collection.

La raison en est qu’une sous-classe de la collection est souvent renvoyée par la méthode testée et que la sous-classe utilisée n’est pas pertinente.

6
talex

Lorsque je lance le code ci-dessous, la condition est false.

if( (new HashSet<>()).equals(new ArrayList<>())){
            System.out.println("They are equal");
        }

Par conséquent, pour assertEquals, c’est true qu’il ne vérifie que les éléments et son ordre d’égalité. Mais pour equals il s’agit de false.

2
Raj