mercredi 26 juillet 2017

Un aperçu sur Stream API dans Java 8

L'API Stream dans Java 8 est utilisé pour travailler avec les collections, pour pouvoir écrire le code dans le style fonctionnel. Grâce à sa simplicité Stream est devenu très populaire entre les programmeurs. Selon la description officielle, la bibliothèque « Java.util.stream » -  nous permet de faire plusieurs opérations dans le style fonctionnel avec des collections d'éléments, tels comme les transformations de MapReduce, etc. L'API contient les opérations « intermédiaires », comme Stream.map ou Stream.filter, mais aussi les opérations « finales » comme Stream.forEach ou Stream.reduce. L'opération « intermédiaire » ne serait jamais exécutées avant l'opération « finale » (p.e. Stream.map  ne serait pas exécutée avant Stream.reduce, mémé si vous le mettez avant dans le code). Un tel comportement s'appelle LAZY.

Une autre grande caractéristique de l'API Stream c'est la parallélisation des sources - parallelStream () qui vient utilisée pour améliorer les performances pour traiter des grandes quantités de données. Les flux parallèles peuvent accélérer l'exécution pour certains types de transactions. Je les utilise quand je sais que la collection est trop grande pour être gérée avec « ForkJoin. » Plus d'informations sur la bibliothèque ForkJoin peut lire ici: http://www.baeldung.com/java-fork-join.

Retournons à nos moutons et nous considérerons un exemple pratique. Un exemple simple de recherche d'un valeur min et d'un valeur max dans une collection.

ArrayList testValues = new ArrayList();
testValues.add(0,15);
testValues.add(1,1);
testValues.add(2,2);
testValues.add(3,100);
testValues.add(4,50);
Optional
maxValue = testValues.stream().max(Integer::compareTo);
System.out.println("MaxValue="+maxValue);
Optional
minValue = testValues.stream().min(Integer::compareTo);
System.out.println("MinValue="+minValue); 




Autre exemple un peu plus compliqué où l'on ajoute une exception (quand la valeur maximale est null):

ArrayList testValuesNull = new ArrayList();
testValuesNull.add(0,null);
testValuesNull.add(1,1);
testValuesNull.add(2,2);
testValuesNull.add(3,70);
testValuesNull.add(4,50);
Optional maxValueNotNull = testValuesNull.stream().filter((p) -> p != null).max(Integer::compareTo);
System.out.println("maxValueNotNull="+maxValueNotNull);



On peut aller encore plus loin et créer une collection que s'appelle « camp sportif » composé des champs « Nom » « Nombre de jours passés dans le camp sportif »

public class SportsCamp 

{ 
   private String name;//Nom
   private Integer day;//Nombre de jours    

   public SportsCamp(String name, int day) 
   { 
     this.name = name;      
     this.day = day; 
   } 
   public String getName() return name;
   public void setName(String name) { this.name = name; } 
   public Integer getDay() { return day; } 
   public void setDay(Integer day) { this.day = day; } 
}


Avec les nouvelles données on pourrait exécuter plusieurs opérations, p.e. trouver qui a passé plus de jours dans le camp sportif.

import java.util.Arrays;
import java.util.Collection;
public class Start
{
   public static void main(String[] args)
   {
     Collection<SportsCamp>
sport = Arrays.asList( new SportsCamp("Jean", 5), new SportsCamp("Pierre", 7), new SportsCamp("Anne", 10) );
     String name = sport.stream().max((p1,p2) ->           p1.getDay().compareTo(p2.getDay())).get().getName();
     System.out.println("Name="+name);
   }
}

Cet exemple nous va retourner le nom d'Anne - cela qui a passé plus de jours dans le camp sportif. Comme j'ai déjà dit, les opérations sont divisés en « intermédiaire » et « finales ». Dans l'exemple ci-dessus, nous pouvons ajouter un nouveau filtre pour le nom « Jean» et obtenir la fréquence, avec laquelle ce nom apparaît dans la collection:


long countName = sport.stream().filter((p) -> p.getName() != null && p.getName().equals("Jean")).count();
System.out.println("countName="+countName);

Evidemment le résultat sera = à 1 (jusqu'à ce que vous ajoutez un autre « Jean» à notre collection).
On peut aussi utiliser parallelStream () pour compter les noms:

long countNameParallel = sport.parallelStream().filter((p) -> p.getName() != null && p.getName().equals("Jean")).count();
System.out.println("countNameParallel=" + countNameParallel);

L'efficacité de parallelStream () se voit mieux sur les serveurs haut-gamme (multi-core) avec de grandes quantités de données. Il est la question de tester et d'ajuster les paramètres du serveur.


L'autre exemple serait de regarder le Map / Reduce, ou pour le moment on va regarder juste le reduce. Reduce vient utilisée pour « construire » les composants , en termes simples, si on veut produir une nouvelle instance d'objet a la maniere "agrégée", en ajoutant d'autres éléments. P.e. calculer tous les jours de tous que les participants ont passé ensemble dans le domaine sportif.


Integer daySum = sport.stream().reduce(0, (sum, p) -> sum += p.getDay(), (sum1, sum2) -> sum1 + sum2);
System.out.println("DaySize=" + daySum);//résultat = 22

Avec ce mode de réalisation, reduce 
prend les trois valeurs: 1.identifieur, 2.accumulateur, 3.résultat.

Aucun commentaire:

Enregistrer un commentaire