拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 Java中如何比较两个列表忽略的顺序?

Java中如何比较两个列表忽略的顺序?

白鹭 - 2021-11-24 826 0 0

1.概述

有时在编写单元测试时,我们需要对列表进行顺序不可知的比较。在这个简短的教程中,我们将研究如何编写此类单元测试的不同示例。

2.设定

根据List#equals Java文档,如果两个列表包含相同顺序的相同元素,则两个列表相等。因此,我们不能只使用equals方法,而是要进行顺序不可知比较。

在本教程中,我们将使用这三个列表作为测试的示例输入:

List first = Arrays.asList(1, 3, 4, 6, 8);

 List second = Arrays.asList(8, 1, 6, 3, 4);

 List third = Arrays.asList(1, 3, 3, 6, 6);

有多种方法可用于顺序不可知比较。让我们一一看一下。

3.使用JUnit

JUnit是一个众所周知的框架,用于Java生态系统中的单元测试。

assertTrueassertFalse方法使用以下逻辑比较两个列表的相等性。

在这里,我们检查两个列表的大小,并检查第一个列表是否包含第二个列表的所有元素,反之亦然。尽管此解决方案有效,但可读性不高。现在让我们来看一些替代方案:

@Test

 public void whenTestingForOrderAgnosticEquality_ShouldBeTrue() {

 assertTrue(first.size() == second.size() && first.containsAll(second) && second.containsAll(first));

 }

在第一个测试中,比较两个列表的大小,然后检查两个列表中的元素是否相同。当这两个条件都返回true,我们的测试将通过。

现在让我们看一下失败的测试:

@Test

 public void whenTestingForOrderAgnosticEquality_ShouldBeFalse() {

 assertFalse(first.size() == third.size() && first.containsAll(third) && third.containsAll(first));

 }

相反,在此版本的测试中,尽管两个列表的大小相同,但所有元素都不匹配。

4.使用AssertJ

AssertJ是一个开源社区驱动的库,用于在Java测试中编写流畅而丰富的断言。

要在我们的maven项目中使用它,让我们pom.xml文件中assertj-core依赖项:

<dependency>

 <groupId>org.assertj</groupId>

 <artifactId>assertj-core</artifactId>

 <version>3.16.1</version>

 </dependency>

让我们编写一个测试来比较相同元素和相同大小的两个列表实例的相等性:

@Test

 void whenTestingForOrderAgnosticEqualityBothList_ShouldBeEqual() {

 assertThat(first).hasSameElementsAs(second);

 }

在此示例中,我们first验证包含给定可迭代元素的所有元素,并且没有其他任何顺序。这种方法的主要局限性是hasSameElementsAs方法将忽略重复项。

让我们在实践中看一下这是什么意思:

@Test

 void whenTestingForOrderAgnosticEqualityBothList_ShouldNotBeEqual() {

 List a = Arrays.asList("a", "a", "b", "c");

 List b = Arrays.asList("a", "b", "c");

 assertThat(a).hasSameElementsAs(b);

 }

在此测试中,尽管我们具有相同的元素,但是两个列表的大小并不相等,但是断言仍然是正确的,因为它忽略了重复项。为了使其正常工作,我们需要为两个列表添加一个大小检查:

assertThat(a).hasSize(b.size()).hasSameElementsAs(b);

确实添加了对我们两个列表的大小的检查,然后添加方法hasSameElementsAs确实会按预期失败。

5.使用Hamcrest

如果我们已经在使用Hamcrest或要使用它来编写单元测试,则可以通过以下Matchers#containsInAnyOrder方法进行不可知的订单比较。

要在我们的Maven项目中使用Hamcrest,让我们pom.xml文件中hamcrest-all依赖项:

<dependency>

 <groupId>org.hamcrest</groupId>

 <artifactId>hamcrest-all</artifactId>

 <version>1.3</version>

 </dependency>

让我们看一下测试:

@Test

 public void whenTestingForOrderAgnosticEquality_ShouldBeEqual() {

 assertThat(first, Matchers.containsInAnyOrder(second.toArray()));

 }

在这里,方法containsInAnyOrder Iterables创建了与订单无关的匹配器,该匹配器与检查的Iterable元素进行匹配。此测试匹配两个列表中的元素,而忽略列表中元素的顺序。

值得庆幸的是,该解决方案不会遇到与上一节所述相同的问题,因此我们不需要显式比较大小。

6.使用Apache Commons

除了JUnit,Hamcrest或AssertJ之外,我们可以使用的另一个库或框架是Apache CollectionUtils 。它提供了适用于广泛使用案例的常用操作的实用方法,并帮助我们避免编写样板代码。

要在我们的maven项目中使用它,让我们pom.xml文件中commons-collections4依赖项:

<dependency>

 <groupId>org.apache.commons</groupId>

 <artifactId>commons-collections4</artifactId>

 <version>4.4</version>

 </dependency>

这是一个使用CollectionUtils的测试:

@Test

 public void whenTestingForOrderAgnosticEquality_ShouldBeTrueIfEqualOtherwiseFalse() {

 assertTrue(CollectionUtils.isEqualCollection(first, second));

 assertFalse(CollectionUtils.isEqualCollection(first, third));

 }

如果给定的集合包含具有相同基数isEqualCollection方法将返回true 。否则,它返回false

7.结论

在本文中,我们探讨了如何检查两个List实例的相等性,这两个List实例的顺序不同。

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *