1. 简介
Groovy 是一门与 Java 兼容的语言,它在 Java 的基础上提供了大量增强功能。
本文将重点介绍 Groovy 在 检查元素是否存在以及在多种集合类型中查找元素时的便利方法。
2. 判断元素是否存在
我们先来看如何判断某个集合中是否包含特定元素。
2.1. List
Java 中的 java.util.List
提供了以下几种方式来判断元素是否存在:
✅ contains
方法
✅ indexOf
方法
Groovy 完全兼容 Java,因此这些方法可以直接使用:
def "whenListContainsElement_thenCheckReturnsTrue"() {
given:
def list = ['a', 'b', 'c']
expect:
list.indexOf('a') > -1
list.contains('a')
}
除此之外,Groovy 还引入了一个语法糖 —— 成员运算符(membership operator):
element in list
这个操作符让代码更加简洁直观:
def "whenListContainsElement_thenCheckWithMembershipOperatorReturnsTrue"() {
given:
def list = ['a', 'b', 'c']
expect:
'a' in list
}
2.2. Set
Set 的判断方式和 List 类似,同样支持 contains
和成员运算符:
def "whenSetContainsElement_thenCheckReturnsTrue"() {
given:
def set = ['a', 'b', 'c'] as Set
expect:
set.contains('a')
'a' in set
}
2.3. Map
Map 中可以分别检查 key 和 value 是否存在:
def "whenMapContainsKeyElement_thenCheckReturnsTrue"() {
given:
def map = [a: 'd', b: 'e', c: 'f']
expect:
map.containsKey('a')
!map.containsKey('e')
map.containsValue('e')
}
也可以使用成员运算符来判断 key 是否存在:
def "whenMapContainsKeyElement_thenCheckByMembershipReturnsTrue"() {
given:
def map = [a: 'd', b: 'e', c: 'f']
expect:
'a' in map
'f' !in map
}
⚠️ 注意: 成员运算符在 Map 中的使用要格外小心。它不会直接判断 key 是否存在,而是取出 key 对应的 value 并将其转换为 boolean 值进行判断。
def "whenMapContainsFalseBooleanValues_thenCheckReturnsFalse"() {
given:
def map = [a: true, b: false, c: null]
expect:
map.containsKey('b')
'a' in map
'b' !in map // 实际上是获取 value 后转换为 boolean
'c' !in map
}
如上所示,当 value 为 false
或 null
时都会被判定为 false
,这在某些场景下可能会导致误判。
3. 全部匹配与任意匹配
在实际开发中,我们经常需要判断集合中的元素是否满足某种条件。Groovy 提供了简洁的方法来处理这类需求。
首先,我们定义一个用于示例的类:
class Person {
private String firstname
private String lastname
private Integer age
// constructor, getters and setters
}
3.1. List/Set
使用 Person 对象组成的 List 作为示例:
private final personList = [
new Person("Regina", "Fitzpatrick", 25),
new Person("Abagail", "Ballard", 26),
new Person("Lucian", "Walter", 30),
]
Java 8 的 Stream API 可以这样使用:
def "givenListOfPerson_whenUsingStreamMatching_thenShouldEvaluateList"() {
expect:
personList.stream().anyMatch { it.age > 20 }
!personList.stream().allMatch { it.age < 30 }
}
Groovy 提供了更简洁的写法:
def "givenListOfPerson_whenUsingCollectionMatching_thenShouldEvaluateList"() {
expect:
personList.any { it.age > 20 }
!personList.every { it.age < 30 }
}
3.2. Map
定义一个以 firstname 为 key 的 Map:
private final personMap = [
Regina : new Person("Regina", "Fitzpatrick", 25),
Abagail: new Person("Abagail", "Ballard", 26),
Lucian : new Person("Lucian", "Walter", 30)
]
使用 Stream API 的方式:
def "givenMapOfPerson_whenUsingStreamMatching_thenShouldEvaluateMap"() {
expect:
personMap.keySet().stream()
.anyMatch { it == "Regina" }
!personMap.keySet().stream()
.allMatch { it == "Albert" }
!personMap.values().stream()
.allMatch { it.age < 30 }
personMap.entrySet().stream()
.anyMatch { it.key == "Abagail" && it.value.lastname == "Ballard" }
}
Groovy 的方式更加直观:
def "givenMapOfPerson_whenUsingCollectionMatching_thenShouldEvaluateMap"() {
expect:
personMap.keySet().any { it == "Regina" }
!personMap.keySet().every { it == "Albert" }
!personMap.values().every { it.age < 30 }
personMap.any { firstname, person -> firstname == "Abagail" && person.lastname == "Ballard" }
}
Groovy 不仅简化了 Stream API 的使用,还允许我们直接在 Map 上进行判断,无需调用 entrySet()
。
4. 查找一个或多个元素
4.1. List/Set
使用 Stream API 查找元素:
def "givenListOfPerson_whenUsingStreamFind_thenShouldReturnMatchingElements"() {
expect:
personList.stream().filter { it.age > 20 }.findAny().isPresent()
!personList.stream().filter { it.age > 30 }.findAny().isPresent()
personList.stream().filter { it.age > 20 }.findAll().size() == 3
personList.stream().filter { it.age > 30 }.findAll().isEmpty()
}
Groovy 的写法更加简洁:
def "givenListOfPerson_whenUsingCollectionFind_thenShouldReturnMatchingElements"() {
expect:
personList.find { it.age > 20 } == new Person("Regina", "Fitzpatrick", 25)
personList.find { it.age > 30 } == null
personList.findAll { it.age > 20 }.size() == 3
personList.findAll { it.age > 30 }.isEmpty()
}
✅ 优势: 无需手动创建 Stream,直接使用集合方法即可。
4.2. Map
Map 中可以查找 key、value 或 entry。这里我们只展示 entry 的查找方式。
使用 Stream API:
def "givenMapOfPerson_whenUsingStreamFind_thenShouldReturnElements"() {
expect:
personMap.entrySet().stream()
.filter { it.key == "Abagail" && it.value.lastname == "Ballard" }
.findAny()
.isPresent()
personMap.entrySet().stream()
.filter { it.value.age > 20 }
.findAll()
.size() == 3
}
Groovy 的方式:
def "givenMapOfPerson_whenUsingCollectionFind_thenShouldReturnElements"() {
expect:
personMap.find { it.key == "Abagail" && it.value.lastname == "Ballard" }
personMap.findAll { it.value.age > 20 }.size() == 3
}
✅ 优势显著: 无需调用 entrySet()
,直接在 Map 上进行操作,语法更加自然。
5. 总结
本文介绍了 Groovy 如何简化集合中元素的查找和判断操作,包括:
- 使用成员运算符简化判断逻辑
- 使用
any
和every
判断集合是否满足条件 - 使用
find
和findAll
快速查找元素
这些方法不仅代码更简洁,而且语义更清晰,是 Groovy 开发中常用的技巧。
完整示例代码可从 GitHub 获取。