Filtrage et transformation des collections en goyave

Filtrage et transformation des collections en goyave

1. Vue d'ensemble

Dans ce didacticiel, nous allons illustrer commentfilter and transform collections with Guava.

Nous filtrerons à l'aide de prédicats, transformerons en utilisant les fonctions fournies par la bibliothèque et enfin, nous verrons comment combiner le filtrage et la transformation.

Lectures complémentaires:

Nouveau cours d'eau, comparateur et collecteur à Guava 21

Guide rapide et pratique des outils du package common.collect dans Guava 21.

Read more

Guide de la goyave Multimap

Un petit guide sur Guava Multimap en comparaison avec java.util.Map standard

Read more

Guide du RangeSet Goyave

Apprenez à utiliser le Google Guava RangeSet et ses implémentations à l'aide d'exemples pratiques.

Read more

2. Filtrer une collection

Commençons par un exemple simple defiltering a collection. Nous allons utiliser un prédicat prêt à l'emploi fourni par la bibliothèque et construit via la classe utilitairePredicates:

@Test
public void whenFilterWithIterables_thenFiltered() {
    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Iterable result
      = Iterables.filter(names, Predicates.containsPattern("a"));

    assertThat(result, containsInAnyOrder("Jane", "Adam"));
}

Comme vous pouvez le voir, nous filtrons lesList de noms pour obtenir uniquement les noms qui contiennent le caractère «a» - et nous utilisonsIterables.filter() pour le faire.

Alternativement, nous pouvons également faire bon usage de l'APICollections2.filter():

@Test
public void whenFilterWithCollections2_thenFiltered() {
    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result
      = Collections2.filter(names, Predicates.containsPattern("a"));

    assertEquals(2, result.size());
    assertThat(result, containsInAnyOrder("Jane", "Adam"));

    result.add("anna");
    assertEquals(5, names.size());
}

Quelques points à noter ici - d'abord, la sortie deCollections.filter() esta live view of the original collection - les modifications apportées à l'un seront reflétées dans l'autre.

Il est également important de comprendre que maintenant,the result is constrained by the predicate - si nous ajoutons un élément qui ne satisfait pas quePredicate, unIllegalArgumentException sera lancé:

@Test(expected = IllegalArgumentException.class)
public void givenFilteredCollection_whenAddingInvalidElement_thenException() {
    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result
      = Collections2.filter(names, Predicates.containsPattern("a"));

    result.add("elvis");
}

3. Écriture du filtre personnaliséPredicate

Ensuite, écrivons nos propresPredicate au lieu d'utiliser celui fourni par la bibliothèque. Dans l'exemple suivant, nous allons définir un prédicat qui n'obtient que les noms commençant par "A" ou "J":

@Test
public void whenFilterCollectionWithCustomPredicate_thenFiltered() {
    Predicate predicate = new Predicate() {
        @Override
        public boolean apply(String input) {
            return input.startsWith("A") || input.startsWith("J");
        }
    };

    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result = Collections2.filter(names, predicate);

    assertEquals(3, result.size());
    assertThat(result, containsInAnyOrder("John", "Jane", "Adam"));
}

4. Combiner plusieurs prédicats

Nous pouvons combiner plusieurs prédicats en utilisantPredicates.or() etPredicates.and(). Dans l'exemple suivant, nous filtrons unList de noms pour obtenir les noms commençant par «J» ou ne contenant pas «a»:

@Test
public void whenFilterUsingMultiplePredicates_thenFiltered() {
    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result = Collections2.filter(names,
      Predicates.or(Predicates.containsPattern("J"),
      Predicates.not(Predicates.containsPattern("a"))));

    assertEquals(3, result.size());
    assertThat(result, containsInAnyOrder("John", "Jane", "Tom"));
}

5. Supprimer les valeurs nulles lors du filtrage d'une collection

Nous pouvons nettoyer les valeursnull d'une collection en la filtrant avecPredicates.notNull() comme dans l'exemple suivant:

@Test
public void whenRemoveNullFromCollection_thenRemoved() {
    List names =
      Lists.newArrayList("John", null, "Jane", null, "Adam", "Tom");
    Collection result =
      Collections2.filter(names, Predicates.notNull());

    assertEquals(4, result.size());
    assertThat(result, containsInAnyOrder("John", "Jane", "Adam", "Tom"));
}

6. Vérifier si tous les éléments d'une collection correspondent à une condition

Ensuite, vérifions si tous les éléments d'une collection correspondent à une certaine condition. Nous utiliseronsIterables.all() pour vérifier si tous les noms contiennent «n» ou «m», puis nous vérifierons si tous les éléments contiennent «a»:

@Test
public void whenCheckingIfAllElementsMatchACondition_thenCorrect() {
    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");

    boolean result = Iterables.all(names, Predicates.containsPattern("n|m"));
    assertTrue(result);

    result = Iterables.all(names, Predicates.containsPattern("a"));
    assertFalse(result);
}

7. Transformez une collection

Voyons maintenant comment faire pourtransform a collection using a Guava Function. Dans l'exemple suivant - nous transformons unList de noms en unList deIntegers (longueur du nom) avecIterables.transform():

@Test
public void whenTransformWithIterables_thenTransformed() {
    Function function = new Function() {
        @Override
        public Integer apply(String input) {
            return input.length();
        }
    };

    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Iterable result = Iterables.transform(names, function);

    assertThat(result, contains(4, 4, 4, 3));
}

Nous pouvons également utiliser l'APICollections2.transform() comme dans l'exemple suivant:

@Test
public void whenTransformWithCollections2_thenTransformed() {
    Function func = new Function(){
        @Override
        public Integer apply(String input) {
            return input.length();
        }
    };

    List names =
      Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result = Collections2.transform(names, func);

    assertEquals(4, result.size());
    assertThat(result, contains(4, 4, 4, 3));

    result.remove(3);
    assertEquals(3, names.size());
}

Notez que la sortie deCollections.transform() esta live view of the original Collection - les modifications apportées à l'un affectent l'autre.

Et - comme avant - si nous essayons d'ajouter un élément à la sortieCollection, unUnsupportedOperationException sera lancé.

8. CréerFunction à partir dePredicate

Nous pouvons également créer desFunction à partir d'unPredicate en utilisantFunctions.fromPredicate(). Il s'agit bien sûr d'une fonction qui transforme les entrées enBoolean, selon la condition du prédicat.

Dans l'exemple suivant, nous transformons unList de noms en une liste de booléens où chaque élément représente si le nom contient «m»:

@Test
public void whenCreatingAFunctionFromAPredicate_thenCorrect() {
    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result =
      Collections2.transform(names,
      Functions.forPredicate(Predicates.containsPattern("m")));

    assertEquals(4, result.size());
    assertThat(result, contains(false, false, true, true));
}

9. Composition de deux fonctions

Ensuite, voyons comment transformer une collection en utilisant unFunction composé.

Functions.compose() renvoie la composition de deux fonctions en appliquant le deuxièmeFunction à la sortie des premiersFunction.

Dans l'exemple suivant - le premierFunction transforme le nom en sa longueur, puis le secondFunction transforme la longueur en une valeurboolean qui représente si la longueur du nom est paire:

@Test
public void whenTransformingUsingComposedFunction_thenTransformed() {
    Function f1 = new Function(){
        @Override
        public Integer apply(String input) {
            return input.length();
        }
    };

    Function f2 = new Function(){
        @Override
        public Boolean apply(Integer input) {
            return input % 2 == 0;
        }
    };

    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result =
      Collections2.transform(names, Functions.compose(f2, f1));

    assertEquals(4, result.size());
    assertThat(result, contains(true, true, true, false));
}

10. Combinez le filtrage et la transformation

Et maintenant - voyons une autre API intéressante dont dispose Guava - une API qui nous permettra en fait d'enchaîner le filtrage et la transformation ensemble - lesFluentIterable.

Dans l'exemple suivant - nous filtrons lesList de noms puis les transformons en utilisantFluentIterable:

@Test
public void whenFilteringAndTransformingCollection_thenCorrect() {
    Predicate predicate = new Predicate() {
        @Override
        public boolean apply(String input) {
            return input.startsWith("A") || input.startsWith("T");
        }
    };

    Function func = new Function(){
        @Override
        public Integer apply(String input) {
            return input.length();
        }
    };

    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result = FluentIterable.from(names)
                                               .filter(predicate)
                                               .transform(func)
                                               .toList();

    assertEquals(2, result.size());
    assertThat(result, containsInAnyOrder(4, 3));
}

Il est à noter que, dans certains cas, la version impérative est plus lisible et devrait être préférée à l’approche fonctionnelle.

11. Conclusion

Enfin, nous avons appris à filtrer et à transformer des collections à l’aide de Guava. Nous avons utilisé les APICollections2.filter() etIterables.filter() pour le filtrage, ainsi queCollections2.transform() etIterables.transform() pour transformer les collections.

Enfin, nous avons jeté un coup d'œil à l'API fluente deFluentIterable très intéressante pour combiner à la fois filtrage et transformation.

L'implémentation de tous ces exemples et extraits de codecan be found in the GitHub project - il s'agit d'un projet basé sur Maven, il devrait donc être facile à importer et à exécuter tel quel.