1. Introduction
1.介绍
Groovy provides a substantial number of methods enhancing Java’s core capabilities.
Groovy提供了大量的方法来增强Java的核心能力。
In this tutorial, we’ll show how Groovy does this when checking for an element and finding it in several types of collections.
在本教程中,我们将展示Groovy在检查一个元素并在几种类型的集合中找到它时是如何做到的。
2. Test If Element Is Present
2.测试元素是否存在
First, we’ll focus on just testing if a given collection contains an element.
首先,我们将专注于只测试一个给定的集合是否包含一个元素。
2.1. List
2.1.列表
Java itself provides several ways of checking for an item in a list with java.util.List:
Java本身提供了几种方法来用java.util.List检查列表中的一个项目。
- The contains method
- The indexOf method
As Groovy is a Java-compatible language, we can safely use them.
由于Groovy是一种与Java兼容的语言,我们可以安全地使用它们。
Let’s take a look at an example:
我们来看看一个例子。
@Test
void whenListContainsElement_thenCheckReturnsTrue() {
def list = ['a', 'b', 'c']
assertTrue(list.indexOf('a') > -1)
assertTrue(list.contains('a'))
}
Apart from that, Groovy introduces the membership operator:
除此之外,Groovy引入了成员操作符:。
element in list
It’s one of many syntactic sugar operators provided by Groovy. With its help, we can simplify our code:
它是Groovy提供的众多语法糖运算符之一。在它的帮助下,我们可以简化我们的代码。
@Test
void whenListContainsElement_thenCheckWithMembershipOperatorReturnsTrue() {
def list = ['a', 'b', 'c']
assertTrue('a' in list)
}
2.2. Set
2.2.设计
As with the previous example, we can use the java.util.Set#contains method and the in operator:
和前面的例子一样,我们可以使用java.util.Set#contains方法和in操作符。
@Test
void whenSetContainsElement_thenCheckReturnsTrue() {
def set = ['a', 'b', 'c'] as Set
assertTrue(set.contains('a'))
assertTrue('a' in set)
}
2.3. Map
2.3.地图
In the case of a Map, we can check for either the key or value directly:
在Map的情况下,我们可以直接检查键或值。
@Test
void whenMapContainsKeyElement_thenCheckReturnsTrue() {
def map = [a: 'd', b: 'e', c: 'f']
assertTrue(map.containsKey('a'))
assertFalse(map.containsKey('e'))
assertTrue(map.containsValue('e'))
}
Or use membership operator to find the matching key:
或者使用成员操作符来找到匹配的键。
@Test
void whenMapContainsKeyElement_thenCheckByMembershipReturnsTrue() {
def map = [a: 'd', b: 'e', c: 'f']
assertTrue('a' in map)
assertFalse('f' in map)
}
When used with maps, we should use the membership operator with care because this operator is a bit confusing to use with boolean values. Rather than testing for the presence of the key, the underlying mechanism retrieves the corresponding value from the map and just casts it to boolean:
当与地图一起使用时,我们应该谨慎地使用成员操作符,因为这个操作符在与布尔值一起使用时有点混乱。底层机制不是测试键的存在,而是从地图中检索出相应的值,并直接将其广播为布尔值:。
@Test
void whenMapContainsFalseBooleanValues_thenCheckReturnsFalse() {
def map = [a: true, b: false, c: null]
assertTrue(map.containsKey('b'))
assertTrue('a' in map)
assertFalse('b' in map)
assertFalse('c' in map)
}
As we might see in the above example, it’s also a bit hazardous to use with null values either for the same reason. Groovy casts both false and null to boolean false.
正如我们在上面的例子中所看到的,由于同样的原因,在使用null值时也是有点危险的。Groovy将false和null都转换为布尔值false。
3. All Match and Any Match
3.全部匹配和任何匹配
In most cases, we deal with collections composed of more complex objects. In this section, we’ll show how to check if the given collection contains at least one matching element or if all elements match a given predicate.
在大多数情况下,我们处理的是由更复杂的对象组成的集合。在这一节中,我们将展示如何检查给定的集合是否至少包含一个匹配的元素,或者所有的元素是否匹配一个给定的谓词。
Let’s start by defining a simple class that we’ll use throughout our examples:
让我们从定义一个简单的类开始,我们将在整个例子中使用它。
class Person {
private String firstname
private String lastname
private Integer age
// constructor, getters and setters
}
3.1. List/Set
<3.1.列表/集
This time, we’ll use a simple list of Person objects:
这一次,我们将使用一个简单的Person对象的列表。
private final personList = [
new Person("Regina", "Fitzpatrick", 25),
new Person("Abagail", "Ballard", 26),
new Person("Lucian", "Walter", 30),
]
As we mentioned before, Groovy is a Java-compatible language, so let’s first create an example using the Stream API introduced by Java 8:
正如我们之前提到的,Groovy是一种兼容Java的语言,所以我们首先使用Java 8引入的Stream API创建一个示例。
@Test
void givenListOfPerson_whenUsingStreamMatching_thenShouldEvaluateList() {
assertTrue(personList.stream().anyMatch {it.age > 20})
assertFalse(personList.stream().allMatch {it.age < 30})
}
We can also use the Groovy methods DefaultGroovyMethods#any and DefaultGroovyMethods#every that perform the check directly on the collection:
我们也可以使用Groovy方法DefaultGroovyMethods#any和DefaultGroovyMethods#every,直接对集合执行检查。
@Test
void givenListOfPerson_whenUsingCollectionMatching_thenShouldEvaluateList() {
assertTrue(personList.any {it.age > 20})
assertFalse(personList.every {it.age < 30})
}
3.2. Map
3.2地图
Let’s start by defining a Map of Person objects mapped by Person#firstname:
让我们首先定义一个由Person#firstname映射的Person对象的Map。
private final personMap = [
Regina : new Person("Regina", "Fitzpatrick", 25),
Abagail: new Person("Abagail", "Ballard", 26),
Lucian : new Person("Lucian", "Walter", 30)
]
We can evaluate it by either its keys, values, or by whole entries. Again, let’s first use the Stream API:
我们可以通过其键、值或整个条目来评估它。同样,让我们首先使用Stream API。
@Test
void givenMapOfPerson_whenUsingStreamMatching_thenShouldEvaluateMap() {
assertTrue(personMap.keySet().stream().anyMatch {it == "Regina"})
assertFalse(personMap.keySet().stream().allMatch {it == "Albert"})
assertFalse(personMap.values().stream().allMatch {it.age < 30})
assertTrue(personMap.entrySet().stream().anyMatch
{it.key == "Abagail" && it.value.lastname == "Ballard"})
}
And then, the Groovy Collection API:
然后,Groovy Collection API:。
@Test
void givenMapOfPerson_whenUsingCollectionMatching_thenShouldEvaluateMap() {
assertTrue(personMap.keySet().any {it == "Regina"})
assertFalse(personMap.keySet().every {it == "Albert"})
assertFalse(personMap.values().every {it.age < 30})
assertTrue(personMap.any {firstname, person -> firstname == "Abagail" && person.lastname == "Ballard"})
}
As we can see, Groovy not only adequately replaces the Stream API when manipulating maps but also allows us to perform a check directly on the Map object instead of using the java.util.Map#entrySet method.
我们可以看到,Groovy不仅在操作地图时充分替代了Stream API,而且允许我们直接对Map对象进行检查,而不是使用java.util.Map#entrySet方法。
4. Find One or More Elements in a Collection
4.在一个集合中找到一个或多个元素
4.1. List/Set
4.1.列表/设置
We can also extract elements using predicates. Let’s start with the familiar Stream API approach:
我们也可以使用谓词来提取元素。让我们从熟悉的Stream API方法开始。
@Test
void givenListOfPerson_whenUsingStreamFind_thenShouldReturnMatchingElements() {
assertTrue(personList.stream().filter {it.age > 20}.findAny().isPresent())
assertFalse(personList.stream().filter {it.age > 30}.findAny().isPresent())
assertTrue(personList.stream().filter {it.age > 20}.findAll().size() == 3)
assertTrue(personList.stream().filter {it.age > 30}.findAll().isEmpty())
}
As we can see, the above example uses java.util.Optional for finding a single element as the Stream API forces that approach.
我们可以看到,上面的例子使用java.util.Optional来寻找单个元素,因为Stream API强制使用这种方法。
On the other hand, Groovy offers a much more compact syntax:
另一方面,Groovy提供了一个更紧凑的语法。
@Test
void givenListOfPerson_whenUsingCollectionFind_thenShouldReturnMatchingElements() {
assertNotNull(personList.find {it.age > 20})
assertNull(personList.find {it.age > 30})
assertTrue(personList.findAll {it.age > 20}.size() == 3)
assertTrue(personList.findAll {it.age > 30}.isEmpty())
}
By using Groovy’s API, we can skip creating a Stream and filtering it.
通过使用Groovy的API,我们可以跳过创建一个Stream和过滤它。
4.2. Map
4.2.地图
In the case of a Map, there are several options to choose from. We can find elements amongst keys, values or complete entries. As the first two are basically a List or a Set, in this section we’ll only show an example of finding entries.
在Map的情况下,有几个选项可供选择。我们可以在键、值或完整的条目中查找元素。由于前两者基本上是一个List或一个Set,在本节中我们将只展示一个查找条目的例子。
Let’s reuse our personMap from earlier:
让我们重新使用先前的personMap。
@Test
void givenMapOfPerson_whenUsingStreamFind_thenShouldReturnElements() {
assertTrue(
personMap.entrySet().stream()
.filter {it.key == "Abagail" && it.value.lastname == "Ballard"}
.findAny().isPresent())
assertTrue(
personMap.entrySet().stream()
.filter {it.value.age > 20}
.findAll().size() == 3)
}
And again, the simplified Groovy solution:
再来看看简化的Groovy解决方案。
@Test
void givenMapOfPerson_whenUsingCollectionFind_thenShouldReturnElements() {
assertNotNull(personMap.find {it.key == "Abagail" && it.value.lastname == "Ballard"})
assertTrue(personMap.findAll {it.value.age > 20}.size() == 3)
}
In this case, the benefits are even more significant. We skip the java.util.Map#entrySet method and use a closure with a function provided on the Map.
在这种情况下,好处就更大了。我们跳过java.util.Map#entrySet方法,使用一个闭包,并在Map上提供一个函数。
5. Conclusion
5.结论
In this article, we presented how Groovy simplifies checking for elements and finding them in several types of collections.
在这篇文章中,我们介绍了Groovy如何简化检查元素并在几种类型的集合中找到它们。
As always, the complete code examples used in this tutorial are available over on GitHub.
一如既往,本教程中所使用的完整代码示例可在GitHub上获得。