Trovare elementi nelle collezioni in Groovy

1. Introduzione

Groovy fornisce un numero considerevole di metodi che migliorano le funzionalità principali di Java.

In questo tutorial, mostreremo come Groovy lo fa quando controlla un elemento e lo trova in diversi tipi di raccolte.

2. Verifica se l'elemento è presente

Per prima cosa, ci concentreremo solo sul testare se una data raccolta contiene un elemento.

2.1. Elenco

Java stesso fornisce diversi modi per verificare la presenza di un elemento in un elenco con java.util.List :

  • Il metodo contiene
  • Il metodo indexOf

Poiché Groovy è un linguaggio compatibile con Java, possiamo usarli in sicurezza.

Diamo un'occhiata a un esempio:

@Test void whenListContainsElement_thenCheckReturnsTrue() { def list = ['a', 'b', 'c'] assertTrue(list.indexOf('a') > -1) assertTrue(list.contains('a')) }

A parte questo, Groovy introduce l'operatore di iscrizione:

element in list

È uno dei tanti operatori di zucchero sintattico forniti da Groovy. Con il suo aiuto, possiamo semplificare il nostro codice:

@Test void whenListContainsElement_thenCheckWithMembershipOperatorReturnsTrue() { def list = ['a', 'b', 'c'] assertTrue('a' in list) }

2.2. Impostato

Come con l'esempio precedente, possiamo usare il java.util.Set # contiene il metodo e l' in dell'operatore:

@Test void whenSetContainsElement_thenCheckReturnsTrue() { def set = ['a', 'b', 'c'] as Set assertTrue(set.contains('a')) assertTrue('a' in set) }

2.3. Carta geografica

Nel caso di una mappa , possiamo controllare direttamente la chiave o il valore:

@Test void whenMapContainsKeyElement_thenCheckReturnsTrue() { def map = [a: 'd', b: 'e', c: 'f'] assertTrue(map.containsKey('a')) assertFalse(map.containsKey('e')) assertTrue(map.containsValue('e')) }

Oppure utilizza l'operatore di appartenenza per trovare la chiave corrispondente:

@Test void whenMapContainsKeyElement_thenCheckByMembershipReturnsTrue() { def map = [a: 'd', b: 'e', c: 'f'] assertTrue('a' in map) assertFalse('f' in map) }

Quando viene utilizzato con le mappe, dovremmo usare l'operatore di appartenenza con attenzione perché questo operatore è un po 'confuso da usare con i valori booleani. Piuttosto che testare la presenza della chiave, il meccanismo sottostante recupera il valore corrispondente dalla mappa e lo lancia in booleano:

@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) }

Come potremmo vedere nell'esempio sopra, è anche un po 'pericoloso usare con valori nulli per lo stesso motivo. Groovy esegue il cast di false e null in boolean false .

3. All Match e Any Match

Nella maggior parte dei casi, ci occupiamo di raccolte composte da oggetti più complessi. In questa sezione, mostreremo come verificare se la raccolta data contiene almeno un elemento corrispondente o se tutti gli elementi corrispondono a un determinato predicato.

Iniziamo definendo una semplice classe che useremo nei nostri esempi:

class Person { private String firstname private String lastname private Integer age // constructor, getters and setters }

3.1. Elenco / Set

Questa volta useremo un semplice elenco di oggetti Person :

private final personList = [ new Person("Regina", "Fitzpatrick", 25), new Person("Abagail", "Ballard", 26), new Person("Lucian", "Walter", 30), ]

Come accennato prima, Groovy è un linguaggio compatibile con Java , quindi creiamo prima un esempio utilizzando l' API Stream introdotta da Java 8:

@Test void givenListOfPerson_whenUsingStreamMatching_thenShouldEvaluateList() { assertTrue(personList.stream().anyMatch {it.age > 20}) assertFalse(personList.stream().allMatch {it.age < 30}) }

Possiamo anche utilizzare i metodi Groovy DefaultGroovyMethods # any e DefaultGroovyMethods # every che eseguono il controllo direttamente sulla raccolta:

@Test void givenListOfPerson_whenUsingCollectionMatching_thenShouldEvaluateList() { assertTrue(personList.any {it.age > 20}) assertFalse(personList.every {it.age < 30}) }

3.2. Carta geografica

Iniziamo definendo una mappa degli oggetti Persona mappati da Persona # nome :

private final personMap = [ Regina : new Person("Regina", "Fitzpatrick", 25), Abagail: new Person("Abagail", "Ballard", 26), Lucian : new Person("Lucian", "Walter", 30) ]

Possiamo valutarlo in base alle sue chiavi, ai valori o alle voci intere. Ancora una volta, usiamo prima l' API Stream :

@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"}) }

E poi, l'API di Groovy Collection:

@Test void givenMapOfPerson_whenUsingCollectionMatching_thenShouldEvaluateMap() { assertTrue(personMap.keySet().any {it == "Regina"}) assertFalse(personMap.keySet().every {it == "Albert"}) assertFalse(personMap.values().every {it.age  firstname == "Abagail" && person.lastname == "Ballard"}) }

Come possiamo vedere, Groovy non solo sostituisce adeguatamente l' API Stream durante la manipolazione delle mappe, ma ci consente anche di eseguire un controllo direttamente sull'oggetto Map invece di utilizzare il metodo java.util.Map # entrySet .

4. Trova uno o più elementi in una raccolta

4.1. Elenco / Set

Possiamo anche estrarre elementi usando predicati. Cominciamo con l' approccio familiare dell'API Stream :

@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()) }

Come possiamo vedere, l'esempio precedente utilizza java.util.Optional per trovare un singolo elemento poiché l' API Stream impone tale approccio.

D'altra parte, Groovy offre una sintassi molto più compatta:

@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()) }

Utilizzando l'API di Groovy, possiamo saltare la creazione di uno stream e filtrarlo .

4.2. Map

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.

Let's reuse our personMap from earlier:

@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:

@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.

5. Conclusion

In this article, we presented how Groovy simplifies checking for elements and finding them in several types of collections.

Come sempre, gli esempi di codice completi utilizzati in questo tutorial sono disponibili su GitHub.