1. Введение
Groovy предоставляет значительное количество методов, расширяющих основные возможности Java.
В этом руководстве мы покажем, как это делает Groovy при проверке элемента и его поиске в нескольких типах коллекций .
2. Проверьте, присутствует ли элемент
Во-первых, мы сосредоточимся только на проверке того, содержит ли данная коллекция элемент.
2.1. Список
Сама Java предоставляет несколько способов проверки элемента в списке с помощью java.util.List
:
- Метод
содержит
_ - Метод
indexOf
_
Поскольку Groovy — это язык, совместимый с Java, мы можем безопасно их использовать.
Давайте рассмотрим пример:
@Test
void whenListContainsElement_thenCheckReturnsTrue() {
def list = ['a', 'b', 'c']
assertTrue(list.indexOf('a') > -1)
assertTrue(list.contains('a'))
}
Кроме того, Groovy вводит оператор принадлежности:
element in list
Это один из многих операторов синтаксического сахара, предоставляемых Groovy. С его помощью мы можем упростить наш код:
@Test
void whenListContainsElement_thenCheckWithMembershipOperatorReturnsTrue() {
def list = ['a', 'b', 'c']
assertTrue('a' in list)
}
2.2. Установлен
Как и в предыдущем примере, мы можем использовать метод 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
мы можем напрямую проверить либо ключ, либо значение:
@Test
void whenMapContainsKeyElement_thenCheckReturnsTrue() {
def map = [a: 'd', b: 'e', c: 'f']
assertTrue(map.containsKey('a'))
assertFalse(map.containsKey('e'))
assertTrue(map.containsValue('e'))
}
Или используйте оператор членства, чтобы найти соответствующий ключ:
@Test
void whenMapContainsKeyElement_thenCheckByMembershipReturnsTrue() {
def map = [a: 'd', b: 'e', c: 'f']
assertTrue('a' in map)
assertFalse('f' in map)
}
При использовании с картами мы должны использовать оператор принадлежности с осторожностью, потому что этот оператор немного сбивает с толку при использовании с логическими значениями. Вместо проверки наличия ключа базовый механизм извлекает соответствующее значение из карты и просто приводит его к логическому значению:
@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)
}
Как мы могли видеть в приведенном выше примере, также немного опасно использовать значения null
по той же причине. Groovy приводит как false
, так и null
к логическому значению false
.
3. Все совпадения и любые совпадения
В большинстве случаев мы имеем дело с коллекциями, состоящими из более сложных объектов. В этом разделе мы покажем, как проверить, содержит ли данная коллекция хотя бы один соответствующий элемент или все элементы соответствуют заданному предикату.
Давайте начнем с определения простого класса, который мы будем использовать в наших примерах:
class Person {
private String firstname
private String lastname
private Integer age
// constructor, getters and setters
}
3.1. Список/Набор
На этот раз мы будем использовать простой список объектов Person
:
private final personList = [
new Person("Regina", "Fitzpatrick", 25),
new Person("Abagail", "Ballard", 26),
new Person("Lucian", "Walter", 30),
]
Как мы упоминали ранее, Groovy — это язык, совместимый с Java , поэтому давайте сначала создадим пример, используя Stream
API , представленный в Java 8:
@Test
void givenListOfPerson_whenUsingStreamMatching_thenShouldEvaluateList() {
assertTrue(personList.stream().anyMatch {it.age > 20})
assertFalse(personList.stream().allMatch {it.age < 30})
}
Мы также можем использовать методы 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
of Person
, отображаемых с помощью Person#firstname
:
private final personMap = [
Regina : new Person("Regina", "Fitzpatrick", 25),
Abagail: new Person("Abagail", "Ballard", 26),
Lucian : new Person("Lucian", "Walter", 30)
]
Мы можем оценить его либо по его ключам, значениям, либо по целым записям. Опять же, давайте сначала воспользуемся 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"})
}
А затем API коллекции Groovy:
@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"})
}
Как мы видим, Groovy не только адекватно заменяет Stream
API при манипулировании картами, но и позволяет выполнять проверку непосредственно на объекте Map
вместо использования метода java.util.Map#entrySet
.
4. Найдите один или несколько элементов в коллекции
4.1. Список/Набор
Мы также можем извлекать элементы с помощью предикатов. Начнем со знакомого подхода 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())
}
Как мы видим, в приведенном выше примере используется java.util.Optional
для поиска одного элемента, поскольку Stream
API вынуждает использовать этот подход.
С другой стороны, 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())
}
Используя Groovy API, мы можем пропустить создание потока
и его фильтрацию .
4.2. карта
В случае карты
есть несколько вариантов на выбор. Мы можем найти элементы среди ключей, значений или полных записей. Поскольку первые два в основном представляют собой список
или набор
, в этом разделе мы покажем только пример поиска записей.
Давайте повторно используем нашу карту 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)
}
И снова упрощенное решение 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)
}
В этом случае преимущества еще значительнее. Мы пропускаем метод java.util.Map#entrySet
и используем замыкание с функцией, предоставленной на карте
.
5. Вывод
В этой статье мы представили, как Groovy упрощает проверку элементов и их поиск в нескольких типах коллекций.
Как всегда, полные примеры кода, используемые в этом руководстве, доступны на GitHub .