1. 简介

Hamcrest是Java中用于编写匹配器对象的流行框架,提供了一种表达性强的条件匹配方式。其中hasItems()contains()containsInAnyOrder()这些匹配器,让我们能断言集合中元素的存在性和顺序性。本文将深入剖析每个匹配器的功能、差异及适用场景。

2. 元素顺序处理

本节探讨三个匹配器对集合元素顺序的不同要求。

2.1. hasItems()

hasItems()匹配器只检查集合是否包含特定元素,完全无视元素顺序

List<String> myList = Arrays.asList("apple", "banana", "cherry");

assertThat(myList, hasItems("apple", "cherry", "banana"));
assertThat(myList, hasItems("banana", "apple", "cherry"));

2.2. containsInAnyOrder()

hasItems()类似,containsInAnyOrder()同样忽略元素顺序。它只关心指定元素是否全部存在,顺序无所谓

assertThat(myList, containsInAnyOrder("apple", "cherry", "banana"));
assertThat(myList, containsInAnyOrder("banana", "apple", "cherry"));

2.3. contains()

contains()匹配器则对顺序敏感。它要求集合必须按指定顺序精确包含所有元素

assertThat(myList, contains("apple", "banana", "cherry"));
assertThat(myList, not(contains("banana", "apple", "cherry")));

第一个断言通过,因为元素顺序完全匹配。第二个断言使用not()匹配器,验证myList不包含乱序元素。

3. 元素数量要求

本节分析三个匹配器对集合元素数量的处理方式。

3.1. hasItems()

hasItems()不要求集合元素数量完全匹配。它只关注指定元素是否存在,对集合大小和顺序无严格要求

assertThat(myList, hasItems("apple", "banana"));
assertThat(myList, hasItems("apple", "banana", "cherry"));
assertThat(myList, not(hasItems("apple", "banana", "cherry", "date")));

✅ 前两个断言通过,因为所有指定元素都存在
❌ 第三个断言通过,因为集合中不存在"date"元素
⚠️ 注意:当集合包含未指定的额外元素时,断言会失败

3.2. containsInAnyOrder()

hasItems()不同,containsInAnyOrder()要求集合必须包含所有指定元素。顺序无关紧要,但元素必须完全匹配:

assertThat(myList, containsInAnyOrder("apple", "banana", "cherry"));
assertThat(myList, not(containsInAnyOrder("apple", "banana")));

✅ 第一个断言通过,所有元素都存在
❌ 第二个断言通过,因为缺少"cherry"元素

3.3. contains()

containsInAnyOrder()类似,contains()也要求元素数量完全匹配,但必须严格按指定顺序

assertThat(myList, contains("apple", "banana", "cherry"));
assertThat(myList, not(contains("apple", "banana")));

✅ 第一个断言通过,顺序和数量都匹配
❌ 第二个断言通过,因为缺少"cherry"元素

4. 重复元素处理

当集合包含重复元素时,三个匹配器的行为差异明显。

4.1. hasItems()

hasItems()完全忽略重复元素。它只检查指定元素是否存在,不关心出现次数:

List<String> myListWithDuplicate = Arrays.asList("apple", "banana", "cherry", "apple");

assertThat(myListWithDuplicate, hasItems("apple", "banana", "cherry"));

✅ 断言通过,即使"apple"重复出现

4.2. containsInAnyOrder()

containsInAnyOrder()要求元素数量精确匹配,包括重复元素:

assertThat(myList, containsInAnyOrder("apple", "banana", "cherry", "apple"));
assertThat(myListWithDuplicate, not(containsInAnyOrder("apple", "banana", "cherry")));

❌ 第一个断言失败,因为myList没有重复的"apple"
❌ 第二个断言通过,因为测试数据缺少重复的"apple"

4.3. contains()

contains()要求元素序列和数量完全匹配,包括重复元素:

assertThat(myList, not(contains("apple", "banana", "cherry")));

❌ 断言通过,因为myList没有重复的"apple"元素

5. 总结

下表清晰对比了三个匹配器的核心差异:

匹配器 顺序敏感 精确数量 重复元素处理 主要用途
hasItems() ❌ 否 ❌ 否 忽略重复 检查元素是否存在,顺序无关
containsInAnyOrder() ❌ 否 ✅ 是 要求精确匹配 检查所有元素是否存在,顺序无关
contains() ✅ 是 ✅ 是 要求精确匹配 检查元素序列和数量是否完全一致

6. 结论

本文详细分析了Hamcrest中三个常用匹配器的区别:

  • 只关心集合是否包含指定元素(顺序无关)时,使用hasItems()
  • 必须包含所有指定元素但顺序无关时,使用containsInAnyOrder()
  • 必须严格按指定顺序包含所有元素时,使用contains()

简单粗暴的选择原则: ✅ 元素存在性检查 → hasItems()
✅ 元素完整性检查 → containsInAnyOrder()
✅ 元素序列检查 → contains()

所有示例代码已上传至GitHub仓库,欢迎参考实践。


原始标题:Difference Between hasItems(), contains(), and containsInAnyOrder() in Hamcrest | Baeldung