为什么不同类型的空集合相等?

时间:2018-09-06 10:16:31

标签: java collections testng

下面是什么使不同类型相等的机制?

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

5 个答案:

答案 0 :(得分:55)

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

  

断言两个集合以相同的顺序包含相同的元素。如果没有,则抛出AssertionError。

因此将比较集合的内容,如果两个集合为空,则它们相等。

答案 1 :(得分:31)

他们不是...

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

这特定于testng assertEquals

查看该方法的说明文件:

  

断言两个集合以相同的顺序包含相同的元素。

这对我来说很荒谬,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-9 Set::of方法在内部实现了随机化,因此运行的 order (或顺序)将有所不同。

答案 2 :(得分:9)

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

这试图有所帮助,但由于多种原因而效果不佳。

两个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 ....

两个集合可以相同也可以不同,这取决于它们的比较方式。

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

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

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

答案 3 :(得分:6)

因为只收集内容,所以不比较收集类型。

其背后的原因是,通常有一些集合的子类是从经过测试的方法返回的,与使用什么子类无关。

答案 4 :(得分:2)

当我运行以下代码时,条件为false

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

因此assertEquals true 是,它仅检查元素及其顺序是否相等。但是对于equals,它是 false