Introduction à StreamEx

1. Vue d'ensemble

L'une des fonctionnalités les plus intéressantes de Java 8 est l' API Stream - 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 principales:

  • Des moyens plus courts et pratiques pour effectuer les tâches quotidiennes
  • Compatibilité à 100% avec les flux JDK d'origine
  • Convivialité pour le traitement parallèle: toute nouvelle fonctionnalité profite au maximum des flux parallèles
  • Performance et frais généraux minimes. Si StreamEx permet de résoudre la tâche en utilisant moins de code par rapport au Stream standard , il ne devrait pas être beaucoup plus lent que la manière habituelle (et parfois c'est encore plus rapide)

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

2. Configuration de l'exemple

Pour utiliser StreamEx , nous devons ajouter la dépendance suivante au pom.xml :

 one.util streamex 0.6.5 

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

À travers ce tutoriel, nous allons utiliser une classe User simple :

public class User { int id; String name; Role role = new Role(); // standard getters, setters, and constructors }

Et une classe de rôle simple :

public class Role { }

3. Méthodes de raccourci des collecteurs

L'une des opérations de terminal les plus populaires de Streams est l' opération de collecte ; cela permet de reconditionner les éléments Stream dans une collection de notre choix.

Le problème est que le code peut devenir inutilement verbeux 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 un collecteur pour spécifier que nous avons besoin d'une liste , d'un ensemble, d'une carte, d'une liste Inmutable, etc.:

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

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

3.2. Collectionneurs avancés

Un autre raccourci est groupingBy :

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

Cela produira une carte avec le type de clé spécifié dans la référence de méthode, produisant quelque chose de similaire à l'opération group by en SQL.

En utilisant l' API Stream simple , 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 Collectors.joining ():

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

Ce qui prend tous les éléments du Stream a produit une chaîne les concaténant tous.

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

Dans certains scénarios, nous avons une liste d'objets de différents types, et nous devons les filtrer par type:

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

Nous pouvons ajouter des éléments au début ou à la fin de notre 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() and use the Stream as an Iterable:

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

5. Math Operations and Primitive Types Support

StreamEx adds supports for primitive types, as we can see in this self-explaining example:

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

Now let's take an array of double elements in an unordered manner. We want to create an array consisting of the difference between each pair.

We can use the pairMap method to perform this operation:

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

6. Map Operations

6.1. Filtering by Keys

Another useful feature is an ability to create a Stream from a Map and filter the elements by using the values they point at.

In this case, we're taking all non-null values:

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

6.2. Operating on Key-Value Pairs

We can also operate on key-value pairs by creating an EntryStream instance:

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

The special operation EntryStream.of takes a Map and transforms it into a Stream of key-value objects. Then we use flatMapValues operation to transform our list of roles to a Stream of single values.

Next, we can invert the key-value pair, making the User class the key and the Role class the value.

And finally, we can use the grouping operation to transform our map to the inversion of the one received, all with just four operations.

6.3. Key-Value Mapping

We can also map keys and values independently:

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

With this, we can quickly transform our keys or values to another required type.

7. File Operations

Using StreamEx, we can read files efficiently, i.e., without loading full files at once. It's handy while processing large files:

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

Note that we've used remove() method to filter away empty lines.

Point to note here is that StreamEx won't automatically close the file. Hence, we must remember to manually perform closing operation on both file reading and writing occasion to avoid unnecessary memory overhead.

8. Conclusion

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

Comme toujours, le code source complet est disponible à l'adresse over sur GitHub.