«1. Введение
Groovy предоставляет значительное количество методов, расширяющих основные возможности Java.
В этом уроке мы покажем, как Groovy делает это при проверке элемента и поиске его в нескольких типах коллекций.
2. Проверка наличия элемента
Во-первых, мы сосредоточимся только на проверке наличия элемента в данной коллекции.
2.1. Список
Сама Java предоставляет несколько способов проверки элемента в списке с помощью java.util.List:
-
Метод contains Метод 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. Set
Как и в предыдущем примере, мы можем использовать метод 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. Карта
В случае карты мы можем проверить либо ключ, либо значение напрямую:
@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)
}
При использовании с картами мы следует использовать оператор членства с осторожностью, потому что этот оператор немного сбивает с толку при использовании с логическими значениями. Вместо того, чтобы проверять наличие ключа, базовый механизм извлекает соответствующее значение из карты и просто приводит его к логическому значению: нулевые значения либо по той же причине. Groovy приводит как false, так и null к логическому значению false.
@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)
}
3. All Match и Any Match
В большинстве случаев мы имеем дело с коллекциями, состоящими из более сложных объектов. В этом разделе мы покажем, как проверить, содержит ли данная коллекция хотя бы один соответствующий элемент или все элементы соответствуют заданному предикату.
Начнем с определения простого класса, который мы будем использовать в наших примерах:
3.1. List/Set
class Person {
private String firstname
private String lastname
private Integer age
// constructor, getters and setters
}
На этот раз мы будем использовать простой список объектов Person:
Как мы упоминали ранее, Groovy — это язык, совместимый с Java, поэтому давайте сначала создадим пример, используя представленный Stream API. по Java 8:
private final personList = [
new Person("Regina", "Fitzpatrick", 25),
new Person("Abagail", "Ballard", 26),
new Person("Lucian", "Walter", 30),
]
Мы также можем использовать методы Groovy DefaultGroovyMethods#any и DefaultGroovyMethods#every, которые выполняют проверку непосредственно на коллекции:
@Test
void givenListOfPerson_whenUsingStreamMatching_thenShouldEvaluateList() {
assertTrue(personList.stream().anyMatch {it.age > 20})
assertFalse(personList.stream().allMatch {it.age < 30})
}
3.2. Карта
@Test
void givenListOfPerson_whenUsingCollectionMatching_thenShouldEvaluateList() {
assertTrue(personList.any {it.age > 20})
assertFalse(personList.every {it.age < 30})
}
Давайте начнем с определения карты объектов Person, сопоставленных Person#firstname:
Мы можем оценить ее либо по ее ключам, значениям, либо по целым записям. Опять же, давайте сначала воспользуемся Stream API:
private final personMap = [
Regina : new Person("Regina", "Fitzpatrick", 25),
Abagail: new Person("Abagail", "Ballard", 26),
Lucian : new Person("Lucian", "Walter", 30)
]
А затем Groovy Collection 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"})
}
Как мы видим, Groovy не только адекватно заменяет Stream API при манипулировании картами, но также позволяет нам выполнить проверку непосредственно в объекте Map вместо использования метода java.util.Map#entrySet.
@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"})
}
4. Найти один или несколько элементов в коллекции
4.1. List/Set
Мы также можем извлекать элементы, используя предикаты. Давайте начнем со знакомого подхода Stream API:
Как мы видим, в приведенном выше примере используется java.util.Optional для поиска одного элемента, поскольку 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())
}
С другой стороны, Groovy предлагает гораздо более компактный синтаксис:
Используя Groovy API, мы можем пропустить создание потока и его фильтрацию.
@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())
}
4.2. Карта
В случае карты есть несколько вариантов на выбор. Мы можем найти элементы среди ключей, значений или полных записей. Поскольку первые два в основном представляют собой список или набор, в этом разделе мы покажем только пример поиска записей.
Давайте повторно используем нашу карту personMap из предыдущего:
И снова упрощенное решение Groovy:
@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)
}
В этом случае преимущества еще значительнее. Мы пропускаем метод java.util.Map#entrySet и используем замыкание с функцией, предоставляемой на карте.
@Test
void givenMapOfPerson_whenUsingCollectionFind_thenShouldReturnElements() {
assertNotNull(personMap.find {it.key == "Abagail" && it.value.lastname == "Ballard"})
assertTrue(personMap.findAll {it.value.age > 20}.size() == 3)
}
5. Заключение
В этой статье мы представили, как Groovy упрощает проверку элементов и их поиск в нескольких типах коллекций.
Как всегда, полные примеры кода, используемые в этом руководстве, доступны на GitHub.
«