Introduction à StreamEx

Introduction à StreamEx

1. Vue d'ensemble

L'une des fonctionnalités les plus intéressantes de Java 8 est leStream API - qui, en termes simples, est un outil puissant pour traiter des séquences d'éléments.

StreamEx est une bibliothèque qui fournit des fonctionnalités supplémentaires pour l'API Stream standard ainsi que des améliorations de performances.

Voici quelques fonctionnalités de base:

  • Des moyens plus courts et pratiques pour effectuer les tâches quotidiennes

  • Compatibilité à 100{'t0': 'Streams'}vec les JDKStreamsd'origine

  • Convivialité pour le traitement parallèle: toute nouvelle fonctionnalité tire le meilleur parti possible des flux parallèles

  • Performance et frais généraux minimes. SiStreamEx permet de résoudre la tâche en utilisant moins de code que lesStream, standard, cela ne devrait pas être beaucoup plus lent que la méthode habituelle (et parfois même plus rapide)

Dans ce didacticiel, nous présenterons certaines des fonctionnalités de l'APIStreamEx.

2. Mise en place de l'exemple

Pour utiliserStreamEx, nous devons ajouter la dépendance suivante auxpom.xml:


    one.util
    streamex
    0.6.5

La dernière version de la bibliothèque est disponible surMaven Central.

À travers ce tutoriel, nous allons utiliser une simple classeUser:

public class User {
    int id;
    String name;
    Role role = new Role();

    // standard getters, setters, and constructors
}

Et une simple classeRole:

public class Role {
}

3. Méthodes de raccourci des collectionneurs

L'une des opérations de terminal les plus courantes deStreams est l'opérationcollect; cela permet de reconditionner les éléments deStreamdans une collection de notre choix.

Le problème est que le code peut être inutilement détaillé pour des scénarios simples:

users.stream()
  .map(User::getName)
  .collect(Collectors.toList());

3.1. Collecter dans une collection

Maintenant, avec StreamEx, nous n'avons pas besoin de fournir unCollector pour spécifier que nous avons besoin d'unList,Set, Map, InmutableList,, etc.:

List userNames = StreamEx.of(users)
  .map(User::getName)
  .toList();

L'opérationcollect est toujours disponible dans l'API si nous voulons effectuer quelque chose de plus compliqué que de prendre des éléments d'unStream et de les placer dans une collection.

3.2. Collectionneurs avancés

Un autre raccourci estgroupingBy:

Map> role2users = StreamEx.of(users)
  .groupingBy(User::getRole);

Cela produira unMap avec le type de clé spécifié dans la référence de la méthode, produisant quelque chose de similaire au groupe par opération en SQL.

En utilisant l'API simple deStream, nous aurions besoin d'écrire:

Map> role2users = users.stream()
  .collect(Collectors.groupingBy(User::getRole));

Une forme abrégée similaire peut être trouvée pour lesCollectors.joining():

StreamEx.of(1, 2, 3)
  .joining("; "); // "1; 2; 3"

Ce qui prend tous les éléments duStream a produit unString les concaténant tous.

4. Ajout, suppression et sélection d'éléments

Dans certains scénarios,we’ve got a list of objects of different types, and we need to filter them by type:

List usersAndRoles = Arrays.asList(new User(), new Role());
List roles = StreamEx.of(usersAndRoles)
  .select(Role.class)
  .toList();

We can add elements to the start or end of our*Stream*, avec ces opérations pratiques:

List appendedUsers = StreamEx.of(users)
  .map(User::getName)
  .prepend("(none)")
  .append("LAST")
  .toList();

We can remove unwanted null elements using nonNull() et utilisez lesStream commeIterable:

for (String line : StreamEx.of(users).map(User::getName).nonNull()) {
    System.out.println(line);
}

5. Prise en charge des opérations mathématiques et des types primitifs

StreamEx ajoute des supports pour les types primitifs, comme nous pouvons le voir dans cet exemple explicite:

short[] src = {1,2,3};
char[] output = IntStreamEx.of(src)
  .map(x -> x * 5)
  .toCharArray();

Prenons maintenant un tableau d'élémentsdouble d'une manière non ordonnée. Nous voulons créer un tableau composé de la différence entre chaque paire.

Nous pouvons utiliser la méthodepairMap pour effectuer cette opération:

public double[] getDiffBetweenPairs(double... numbers) {
    return DoubleStreamEx.of(numbers)
      .pairMap((a, b) -> b - a)
      .toArray();
}

6. Opérations cartographiques

6.1. Filtrage par clés

Une autre fonctionnalité utile est la possibilité de créer unStream à partir d'unMap et de filtrer les éléments en utilisant les valeurs vers lesquelles ils pointent.

Dans ce cas, nous prenons toutes les valeurs non nulles:

Map nameToRole = new HashMap<>();
nameToRole.put("first", new Role());
nameToRole.put("second", null);
Set nonNullRoles = StreamEx.ofKeys(nameToRole, Objects::nonNull)
  .toSet();

6.2. Fonctionnement sur des paires clé-valeur

Nous pouvons également opérer sur des paires clé-valeur en créant une instanceEntryStream:

public Map> transformMap(
    Map> role2users) {
    Map> users2roles = EntryStream.of(role2users)
     .flatMapValues(List::stream)
     .invert()
     .grouping();
    return users2roles;
}

L'opération spécialeEntryStream.of prend unMap et le transforme en unStream d'objets clé-valeur. Ensuite, nous utilisons l'opérationflatMapValues pour transformer notre liste de rôles en unStream de valeurs uniques.

Ensuite, nous pouvonsinvert la paire clé-valeur, faisant de la classeUser la clé et de la classeRole la valeur.

Et enfin, nous pouvons utiliser l'opérationgrouping pour transformer notre carte en l'inversion de celle reçue, le tout avec seulement quatre opérations.

6.3. Cartographie clé-valeur

Nous pouvons également mapper des clés et des valeurs indépendamment:

Map mapToString = EntryStream.of(users2roles)
  .mapKeys(String::valueOf)
  .mapValues(String::valueOf)
  .toMap();

Avec cela, nous pouvons rapidement transformer nos clés ou valeurs en un autre type requis.

7. Opérations sur les fichiers

En utilisantStreamEx, nous pouvons lire les fichiers efficacement, c'est-à-dire sans charger les fichiers complets à la fois. C’est pratique lors du traitement de gros fichiers:

StreamEx.ofLines(reader)
  .remove(String::isEmpty)
  .forEach(System.out::println);

Notez que nous avons utilisé la méthoderemove() pour filtrer les lignes vides.

Il faut noter ici queStreamEx ne fermera pas automatiquement le fichier. Par conséquent, nous devons nous rappeler d’effectuer manuellement l’opération de fermeture à la fois en lecture et en écriture de fichier pour éviter une surcharge inutile de mémoire.

8. Conclusion

Dans ce didacticiel, nous avons découvertStreamEx et ses différents utilitaires. Il y a beaucoup plus à parcourir - et ils ont une feuille de triche pratiquehere.

Comme toujours, le code source complet est disponibleover on GitHub.