web-dev-qa-db-ja.com

異なるタイプの空のコレクションが等しいのはなぜですか?

異なるタイプを等しくする以下のメカニズムは何ですか?

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

assertEquals(Collection<?> actual, Collection<?> expected)ドキュメント の意味:

2つのコレクションに同じ要素が同じ順序で含まれていることをアサートします。そうでない場合、AssertionErrorがスローされます。

したがって、両方のコレクションが空の場合に等しいコレクションのコンテンツが比較されます。

55
S.K.

ではない...

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

これはtestngassertEqualsに固有です

そのメソッドのドキュメントを見ると、次のように書かれています:

2つのコレクションに同じ要素が同じ順序で含まれていることをアサートします。

そして、これは私にとってばかげています。Setには順序がありません。

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]

したがって、これらを特定のの時点でCollectionと比較すると、興味深い結果が得られます。

さらに悪いことに、Java-9Set::ofメソッドは内部的にランダム化を実装しているため、order(または順序ではない)は実行ごとに異なります。

31
Eugene

Testngは、この方法で実装されたメソッドを呼び出します。

  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);
    }
  }

これは役立つことを試みていますが、いくつかの理由で不十分です。

2つのequalsコレクションは異なるように見える場合があります。

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");

そして

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");

プリント

[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 ....

2つのコレクションは、それらの比較方法に応じて、同じ場合も異なる場合もあります。

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

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

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

コレクションについては、コレクションタイプではなくコンテンツのみが比較されるためです。

その背後にある理論的な理由は、多くの場合、コレクションのサブクラスの一部がテスト済みのメソッドから返され、使用されるサブクラスとは無関係であるということです。

6
talex

以下のコードを実行すると、条件はfalseです。

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

したがって、assertEqualsの場合、要素とその順序が等しいかどうかのみをチェックするのはtrueです。ただし、equalsの場合はfalseです。

2
Raj