SlideShare une entreprise Scribd logo
1  sur  271
Télécharger pour lire hors ligne
JDK 8 & Lambdas 
Lambdas, Streams, Collectors
Pourquoi ont-ils été introduits ?
Pourquoi ont-ils été introduits ? Comment vont-ils changer nos habitudes de programmation ?
Année d’édition 
1994
Année d’édition 
1994 
En stock. Expédié et vendu par Amazon. Emballage cadeau disponible.
Formation Java 8 
6 & 7 février 2014 
BBL
Introduisons les lambdas
Introduisons les lambdas sur un exemple simple
Un exemple très simple 
public class Person { 
private String name ; 
private int age ; 
// constructors 
// getters / setters 
} 
List<Person> list = new ArrayList<>() ; 
Un bon vieux bean 
… et une bonne vieille liste
int sum = 0 ; 
// I need a default value in case 
// the list is empty 
int average = 0 ; 
for (Person person : list) { 
sum += person.getAge() ; 
} 
if (!list.isEmpty()) { 
average = sum / list.size() ; 
} 
Calculons la moyenne des âges des personnes
int sum = 0 ; 
int n = 0 ; 
int average = 0 ; 
for (Person person : list) { 
if (person.getAge() > 20) { 
n++ ; 
sum += person.getAge() ; 
} 
} 
if (n > 0) { 
average = sum / n ; 
} 
Plus dur : pour les personnes de plus de 20 ans
« programmation impérative » 
int sum = 0 ; 
int n = 0 ; 
int average = 0 ; 
for (Person person : list) { 
if (person.getAge() > 20) { 
n++ ; 
sum += person.getAge() ; 
} 
} 
if (n > 0) { 
average = sum / n ; 
} 
Plus dur : pour les personnes de plus de 20 ans
select avg(age) 
from Person 
where age > 20 
… pas une obligation ! 
Ici on décrit le résultat
select avg(age) 
from Person 
where age > 20 
Dans ce cas la base de données mène le calcul comme elle l’entend 
© SQL 1974 
… pas une obligation ! 
Ici on décrit le résultat
Person 
age 
age > 20 
sum 
1ère étape : mapping 
map
Mapping : 
-prend une liste d’un type donné 
-retourne une liste d’un autre type 
-possède le même nombre d’éléments 
1ère étape : mapping 
map 
Person 
age 
age > 20 
sum
2ème étape : filtrage 
filter 
map 
Person 
age 
age > 20 
sum
Filtrage : 
-prend une liste d’un type donné 
-retourne une liste du même type 
-mais avec moins d’éléments 
Person 
age 
age > 20 
sum 
2ème étape : filtrage 
filter 
map
3ème étape : réduction 
reduce 
filter 
map 
Person 
age 
age > 20 
sum
Reduction : agrégation des éléments d’une liste dans un seul élément Ex : moyenne, somme, min, max, etc… 
Person 
age 
age > 20 
sum 
3ème étape : réduction 
reduce 
filter 
map
Comment peut-on modéliser ce traitement ?
La façon JDK 7 
On crée une interface pour modéliser le mapper… 
public interface Mapper<T, V> { 
public V map(T t) ; 
}
Mapper<Person, Integer> mapper = new Mapper<Person, Integer>() { 
public Integer map(Person p) { 
return p.getAge() ; 
} 
} 
La façon JDK 7 
… et on crée une classe anonyme 
public interface Mapper<T, V> { public V map(T t) ; }
AgePredicate predicate = new Predicate<Integer>() { 
public boolean filter(Integer i) { 
return i > 20 ; 
} 
} 
public interface Predicate<T> { public boolean filter(T t) ; } 
La façon JDK 7 
On peut faire la même chose pour le filtrage
Reducer<Integer> reduction = new Reducer<Integer>() { 
public Integer reduce(Integer i1, Integer i2) { 
return i1 + i2 ; 
} 
} 
public interface Reducer<T> { 
public T reduce(T t1, T t2) ; 
} 
La façon JDK 7 
Et enfin pour la réduction
Au final, le pattern map / filter / reduce en JDK 7 : 
1)Créer 3 interfaces 
public interface Mapper<T, V> { public V map(T t) ; } 
public interface Predicate<T> { 
public boolean filter(T t) ; 
} 
public interface Reducer<T> { 
public T reduce(T t1, T t2) ; 
} 
La façon JDK 7
List<Person> persons = ... ; 
int sum = 
persons.map( 
new Mapper<Person, Integer>() { 
public Integer map(Person p) { 
return p.getAge() ; 
} 
}) 
.filter( 
new Filter<Integer>() { 
public boolean filter(Integer age) { 
return age > 20 ; 
} 
}) 
.reduce(0, 
new Reducer<Integer>() { 
public Integer recude(Integer i1, Integer i2) { 
return i1 + i2 ; 
} 
} 
}) ; 
La façon JDK 7 
Au final, le pattern map / filter / reduce en JDK 7 : 
1)Créer 3 interfaces 
2)Et on applique…
List<Person> persons = ... ; int sum = persons.map( new Mapper<Person, Integer>() { public Integer map(Person p) { return p.getAge() ; } }) .filter( new Filter<Integer>() { public boolean filter(Integer age) { return age > 20 ; } }) .reduce(0, new Reducer<Integer>() { public Integer recude(Integer i1, Integer i2) { return i1 + i2 ; } } }) ; 
La façon JDK 7 
Au final, le pattern map / filter / reduce en JDK 7 : 
1)Créer 3 interfaces 
2)Et on applique…
À la façon du JDK 8
mapper = new Mapper<Person, Integer>() { 
public Integer map(Person person) { 
return person.getAge() ; 
} 
} 
La façon du JDK 8 
Prenons l’exemple du Mapper
mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return person.getAge() ; } } 
Prenons l’exemple du Mapper 
La façon du JDK 8
mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return p.getAge() ; } } 
mapper = (Person person) ; 
On prend person 
La façon du JDK 8 
Prenons l’exemple du Mapper
mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return person.getAge() ; } } 
mapper = (Person person) -> ; 
et… 
La façon du JDK 8 
Prenons l’exemple du Mapper
mapper = new Mapper<Person, Integer>() { 
public Integer map(Person person) { // 1 méthode 
return person.getAge() ; 
} 
} 
mapper = (Person person) -> person.getAge() ; 
… on retourne son âge 
La façon du JDK 8 
Prenons l’exemple du Mapper
Prenons l’exemple du Mapper 
Le compilateur reconnaît cette expression comme une implémentation du mapper 
mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return person.getAge() ; } } 
mapper = (Person person) -> person.getAge() ; 
La façon du JDK 8
Que se passe-t-il si … 
… il y a plus d’une ligne de code ? 
Accolades, un return explicite 
mapper = (Person person) -> { System.out.println("Mapping " + person) ; return person.getAge() ; }
Que se passe-t-il si … 
…le type de retour est void ? 
consumer = (Person person) -> p.setAge(p.getAge() + 1) ;
Que se passe-t-il si … 
…la méthode prend plus d’un argument ? 
Ou : 
reducer = (int i1, int i2) -> { 
return i1 + i2 ; 
} 
reducer = (int i1, int i2) -> i1 + i2 ;
La façon du JDK 8 
Comment le compilateur reconnaît-il l’implémentation du mapper ? 
mapper = (Person person) -> person.getAge() ;
Comment le compilateur reconnaît-il l’implémentation du mapper ? 
1)Il ne faut qu’une méthode dans le mapper 
2)Les types des paramètres et le type de retour doivent être compatible 
3)Les exceptions jetées doivent être compatibles 
mapper = (Person person) -> person.getAge() ; 
La façon du JDK 8
D’autres lambdas 
On peut écrire d’autres lambdas facilement : 
mapper = (Person person) -> person.getAge() ; // mapper filter = (int age) -> age > 20 ; // filter reducer = (int i1, int i2) -> i1 + i2 ; // reducer
Et la plupart du temps, le compilateur reconnaît ceci : 
Le type des paramètres peut être omis 
mapper = person -> person.getAge() ; // mapper 
filter = age -> age > 20 ; // filter 
reducer = (i1, i2) -> i1 + i2 ; // reducer 
D’autres lambdas
Une remarque sur la réduction 
Comment cela fonctionne-t-il réellement ?
Réduction 
2 exemples : 
Attention : 
le résultat est toujours reproductible en série 
il ne l’est en général pas en parallèle 
Reducer r1 = (i1, i2) -> i1 + i2 ; // Ok Reducer r2 = (i1, i2) -> i1*i1 + i2*i2 ; // Oooops
Pour le moment 
Une expression lambda est une autre façon 
d’écrire des instances de classes anonymes
Il y a d’autres syntaxes 
On peut écrire : 
Mais on peut aussi écrire : 
mapper = person -> person.getAge() ; 
mapper = Person::getAge ; // méthode non statique
Il y a d’autres syntaxes 
On peut écrire : 
Ou encore : 
sum = (i1, i2) -> i1 + i2 ; 
sum = Integer::sum ; // méthode statique, nouvelle ! 
max = (i1, i2) -> i1 > i2 ? i1 : i2 ; 
max = Integer::max ; // méthode statique, nouvelle !
Il y a d’autres syntaxes 
Encore un autre exemple : 
toLower = String::toLowerCase ; 
// !!!! NON NON NON !!!! 
toLowerFR = String::toLowerCase(Locale.FRANCE) ;
Plus loin sur les lambdas
Questions : 
Comment modéliser une expression lambda ?
Questions : 
Comment modéliser une expression lambda ? 
Puis-je mettre une expression lambda dans une variable ?
Questions : 
Comment modéliser une expression lambda ? 
Puis-je mettre une expression lambda dans une variable ? 
Un lambda est-il un objet ?
Modélisation 
Un lambda = instance d’une « interface fonctionnelle » 
@FunctionalInterface 
public interface Consumer<T> { 
public void accept(T t) ; 
}
Modélisation 
Un lambda = instance d’une « interface fonctionnelle » 
- ne possède qu’une unique méthode 
@FunctionalInterface 
public interface Consumer<T> { 
public void accept(T t) ; 
}
Modélisation 
Un lambda = instance d’une « interface fonctionnelle » 
- ne possède qu’une unique méthode 
- peut être annotée par @FunctionalInterface (optionnel) 
@FunctionalInterface 
public interface Consumer<T> { 
public void accept(T t) ; 
}
Mettre un lambda dans une variable 
Exemple d’un consommateur : 
Consumer<String> c = new Consumer<String>() { 
@Override 
public void accept(String s) { 
System.out.println(s) ; 
} 
} ; 
Consumer<String> c = s -> System.out.println(s) ; 
Donc :
Questions : 
Quel modèle pour un lambda ? 
réponse : une interface fonctionnelle 
Puis-je mettre un lambda dans une variable ? 
réponse : oui 
Un lambda est-il un objet ?
Un lambda est-il un objet ? 
Petit jeu des 7 erreurs (avec une seule erreur) 
Consumer<String> c = new Consumer<String>() { 
@Override 
public void accept(String s) { 
System.out.println(s) ; 
} 
} ; 
Consumer<String> c = s -> System.out.println(s) ;
Un lambda est-il un objet ? 
Petit jeu des 7 erreurs (avec une seule erreur) 
Consumer<String> c = new Consumer<String>() { 
@Override 
public void accept(String s) { 
System.out.println(s) ; 
} 
} ; 
Consumer<String> c = s -> System.out.println(s) ;
Questions : 
Quel modèle pour un lambda ? 
réponse : une interface fonctionnelle 
Puis-je mettre un lambda dans une variable ? 
réponse : oui 
Un lambda est-il un objet ? 
réponse : non
Des lambdas à profusion : 
Java.util.functions
Java.util.functions 
C’est dans ce package que sont les interfaces fonctionnelles 
Il y en a 43
Java.util.functions 
Supplier 
Consumer / BiConsumer 
Function / BiFunction (UnaryOperator / BinaryOperator) 
Predicate / BiPredicate 
En plus des versions construites sur les types primitifs
Supplier 
Un supplier fournit un objet 
public interface Supplier<T> { 
T get() ; 
}
Consumer 
Un consommateur consomme un objet 
public interface Consumer<T> { 
void accept(T t) ; 
} 
Consumer<String> c1 = s -> System.out.println(s) ; 
Consumer<String> c2 = ... ; 
Consumer<String> c3 = c1.andThen(c2) ; 
persons.stream().forEach(c3) ;
Function 
Une fonction prend un objet et retourne un autre objet 
Les fonctions peuvent être chaînées et / ou composées 
BiFunction prend deux arguments au lieu d’un 
UnaryOperator et BinaryOperator opèrent sur un seul type 
public interface Function<T, R> { 
R apply(T t) ; 
}
Predicate 
Un Predicate prend un objet et retourne un booléen 
Il peut être inversé, et composé avec des AND ou OR 
public interface Predicate<T> { 
boolean test(T t) ; 
}
Retour sur 
map / filter / reduce
La façon JDK 7 
Comment implémenter le pattern map / filter / reduce sur List<Person> ?
Mapping d’une liste 
Mapping en JDK 8 avec des lambdas 
List<Person> persons = new ArrayList<>() ; 
List<Integer> ages = 
Lists.map( 
persons, 
person -> person.getAge() 
) ;
Mapping d’une liste 
Mapping en JDK 8 avec des lambdas 
List<Person> persons = new ArrayList<>() ; 
List<Integer> ages = 
Lists.map( 
persons, 
Person::getAge 
) ;
Pattern complet 
Le pattern va ressembler à ça : 
Pour : l’API peut être optimisée sans que l’on ait à toucher au code, super ! 
// pattern map / filter / reduce 
List<Person> persons = ... ; 
List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; 
List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; 
int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;
Pattern complet 
Le pattern va ressembler à ça : 
Pour : l’API peut être optimisée sans que l’on ait à toucher au code, super ! 
Contre… 
// pattern map / filter / reduce 
List<Person> persons = ... ; 
List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; 
List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; 
int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;
Pattern complet 
1) Supposons que persons soit vraiment GRANDE 
// pattern map / filter / reduce 
List<Person> persons = ... ; 
List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; 
List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; 
int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;
Pattern complet 
1) Supposons que persons soit vraiment GRANDE 
2 duplications : ages & agesGT20 
// pattern map / filter / reduce 
List<Person> persons = ... ; 
List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; 
List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; 
int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;
Pattern complet 
1) Supposons que persons soit vraiment GRANDE 
2 duplications : ages & agesGT20 
Que fait-on de ces listes ? On les envoie au GC ! 
// pattern map / filter / reduce 
List<Person> persons = ... ; 
List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; 
List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; 
int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;
Pattern complet 
2) Supposons que nous aillons un reducer : allMatch 
allMatch est vrai si tous les noms sont plus courts que 20 caractères 
Voyons une implémentation possible de allMatch() 
// pattern map / filter / reduce 
List<Person> persons = ... ; 
List<String> names = 
Lists.map(persons, p -> p.getName()) ; 
boolean allMatch = 
Lists.allMatch(names, n -> n.length() < 20) ;
Écriture de allMatch() 
Voici une implémentation basique de allMatch() 
public static <T> boolean allMatch( 
List<? extends T> list, Filter<T> filter) { 
for (T t : list) { 
if (!filter.filter(t)) { 
return false ; 
} 
} 
return true ; 
} 
Pas besoin de parcourir toute la liste !
Pattern complet 
Quand on applique la réduction allMatch()… 
… names a déjà été évaluée ! 
// pattern map / filter / reduce 
List<Person> persons = ... ; 
List<String> names = 
Lists.map(persons, p -> p.getName()) ; 
boolean allMatch = 
Lists.allMatch(names, n.length() < 20) ;
Pattern complet 
Quand on applique la réduction allMatch()… 
… names a déjà été évaluée ! 
Il aurait fallu appliquer le mapping de façon lazy 
// pattern map / filter / reduce 
List<Person> persons = ... ; 
List<String> names = 
Lists.map(persons, p -> p.getName()) ; 
boolean allMatch = 
Lists.allMatch(names, n.length() < 20) ;
Conclusion 
Pour : 1 
Contre : 2 (au moins) 
// pattern map / filter / reduce 
List<Person> persons = ... ; 
List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; 
List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; 
int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;
// pattern map / filter / reduce 
List<Person> persons = ... ; 
List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; 
List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; 
int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ; 
Conclusion 
Pour : 1 
Contre : 2 (au moins)
Conclusion 
Et il en va de même pour celui-ci : 
// pattern map / filter / reduce 
List<Person> persons = ... ; 
List<Integer> ages = persons.map(p -> p.getAge()) ; 
List<Integer> agesGT20 = ages.filter(a -> a > 20) ; 
int sum = agesGT20.reduce(ages, (i1, i2) -> i1 + i2) ;
Conclusion (again) 
On a besoin d’un nouveau concept pour traiter les listes de grande taille de façon efficace
Quel pattern choisir ?
Introduction 
Implémenter le map / filter / reduce sur Collection aurait mené à ceci : 
Et même si cette approche n’est pas viable, c’est une façon agréable d’écrire les choses 
// map / filter / reduce pattern sur Collection 
int sum = persons 
.map(p -> p.getAge()) 
.filter(a -> a > 20) 
.reduce(0, (a1, a2) -> a1 + a2) ;
Introduction 
Conservons le même genre de pattern, en ajoutant un appel intermédiaire 
// map / filter / reduce pattern sur Collection 
int sum = persons.stream() 
.map(p -> p.getAge()) 
.filter(a -> a > 20) 
.reduce(0, (a1, a2) -> a1 + a2) ;
Introduction 
Collection.stream() retourne un Stream : une nouvelle interface 
Nouvelle interface = on a les mains libres ! 
// map / filter / reduce pattern sur Collection 
int sum = persons.stream() 
.map(p -> p.getAge()) 
.filter(a -> a > 20) 
.reduce(0, (a1, a2) -> a1 + a2) ;
Nouvelle interface Collection 
Donc on a besoin d’une nouvelle méthode sur Collection 
public interface Collection<E> { 
// nos bonnes vieilles méthodes 
Stream<E> stream() ; 
}
Nouvelle interface Collection 
Problème : ArrayList ne compile plus… 
Une solution doit être trouvée ! 
public interface Collection<E> { 
// nos bonnes vieilles méthodes 
Stream<E> stream() ; 
}
Nouvelles interfaces
Interfaces Java 8 
Problème : ajouter des méthodes à une interface sans toucher aux implémentations…
Problème : ajouter des méthodes à une interface sans toucher aux implémentations… 
Solution : changer la façon dont les interfaces fonctionnent en Java ! 
Interfaces Java 8
Interfaces Java 8 
ArrayList a besoin de l’implémentation de stream()… 
public interface Collection<E> { 
// nos bonnes vieilles méthodes 
Stream<E> stream() ; 
}
Interfaces Java 8 
Solution : mettons-les dans l’interface ! 
public interface Collection<E> { 
// nos bonnes vieilles méthodes 
default Stream<E> stream() { 
return ... ; 
} 
}
Interfaces Java 8 
Une interface devient-elle une classe abstraite ?
Interfaces Java 8 
Une interface devient-elle une classe abstraite ? 
Non ! 
-une classe abstraite peut avoir des champs et possède un constructeur 
-un appel de méthode d’une classe abstraite (ou pas) est résolu à l’exécution 
-une implémentation par défaut est juste du code, lié à la compilation
Méthodes par défaut 
Cela amène-t-il l’héritage multiple en Java ?
Méthodes par défaut 
Cela amène-t-il l’héritage multiple en Java ? 
Oui, mais on l’a déjà
Méthodes par défaut 
Cela amène-t-il l’héritage multiple en Java ? 
Oui, mais on l’a déjà 
public class String 
implements Serializable, Comparable<String>, CharSequence { 
// ... 
}
Méthodes par défaut 
Ce que l’on a en Java est l’héritage multiple de type
Méthodes par défaut 
Ce que l’on a en Java est l’héritage multiple de type 
Java 8 amène l’héritage multiple d’implémentation
Méthodes par défaut 
Ce que l’on a en Java est l’héritage multiple de type 
Java 8 amène l’héritage multiple d’implémentation 
Ce que l’on a pas, c’est l’héritage multiple d’état
Méthodes par défaut 
Ce que l’on a en Java est l’héritage multiple de type 
Java 8 amène l’héritage multiple d’implémentation 
Ce que l’on a pas, c’est l’héritage multiple d’état 
… et d’ailleurs, on n’en veut pas !
Méthodes par défaut 
Peut-on avoir des conflits ?
Méthodes par défaut 
Peut-on avoir des conflits ? 
Hélas oui…
Méthodes par défaut 
Peut-on avoir des conflits ? 
Hélas oui… 
Il nous faut donc des règles pour les gérer
Méthodes par défaut 
public class C 
implements A, B { 
// ... 
}
Méthodes par défaut 
Exemple #1 
public class C 
implements A, B { 
// ... 
} 
public interface A { 
default String a() { ... } 
} 
public interface B { 
default String a() { ... } 
}
Méthodes par défaut 
Exemple #1 
Erreur de compilation : 
class C inherits unrelated defaults for a() from types A and B 
public class C 
implements A, B { 
// ... 
} 
public interface A { default String a() { ... } } 
public interface B { 
default String a() { ... } 
}
Méthodes par défaut 
Exemple #2 
La classe gagne ! 
public class C 
implements A, B { 
public String a() { ... } 
} 
public interface A { 
default String a() { ... } 
} 
public interface B { 
default String a() { ... } 
}
Méthodes par défaut 
Exemple #3 
Le plus spécifique gagne ! 
public interface A extends B { 
default String a() { ... } 
} 
public interface B { 
default String a() { ... } 
} 
public class C 
implements A, B { 
// ... 
}
Méthodes par défaut 
Retour sur l’exemple #1 
On peut aussi faire un appel explicite 
public interface A { 
default String a() { ... } 
} 
public interface B { 
default String a() { ... } 
} 
public class C 
implements A, B { 
public String a() { return B.super.a() ; } 
}
2 règles simples 
Pour gérer les conflits de l’héritage multiple d’implémentation
2 règles simples 
Pour gérer les conflits de l’héritage multiple d’implémentation 
1)La classe gagne
2 règles simples 
Pour gérer les conflits de l’héritage multiple d’implémentation 
1)La classe gagne 
2)Les implémentations les plus spécifiques gagnent
Un exemple 
On a tous écrit une implémentation d’Iterator : 
public class MyIterator implements Iterator<E> { 
// du code métier super important 
public void remove() { 
throw new UnsupportedOperationException("Naaaaaaan !") ; 
} ; 
}
Un exemple 
Grâce à Java 8 : 
Plus besoin d’écrire ce code ! 
public interface Iterator<E> { default void remove() { throw new UnsupportedOperationException("remove") ; } ; }
Interfaces en Java 8 
Donc on change le concept d’interfaces en Java 8 
public class HelloWorld { 
// souvenir souvenir 
public static void main(String[] args) { 
System.out.println("Hello world!") ; 
} ; 
}
Interfaces en Java 8 
Donc on change le concept d’interfaces en Java 8 
Vraiment… 
public interface HelloWorld { 
// souvenir souvenir 
public static void main(String[] args) { 
System.out.println("Hello world!") ; 
} ; 
}
Interfaces en Java 8 
1)Méthodes par défaut, héritage multiple d’implémentation 
règles pour gérer les conflits, qui s’appliquent à la compilation 
2)Des méthodes statiques dans les interfaces 
Tout ceci va permettre de nouvelles manières d’écrire les APIs
On en sommes-nous ? 
1)On a une nouvelle syntaxe : les lambdas 
2)On a un pattern à implémenter 
3)On a des nouvelles interfaces qui permettent de conserver la compatibilité ascendante
L’API Stream
Qu’est-ce qu’un Stream ? 
D’un point de vue technique : une interface paramétrée 
« un stream de String »
Qu’est-ce qu’un Stream ? 
D’un point de vue technique : une interface paramétrée 
D’autres interfaces pour les types primitifs : 
« un stream de String » 
IntStream, LongStream, DoubleStream
Une nouvelle notion 
1)Un stream ne porte pas de donnée 
Il s’agit juste d’un objet sur lequel on peut déclarer des opérations
Une nouvelle notion 
1)Un stream ne porte pas de donnée 
2)Un stream ne peut pas modifier sa source 
Conséquence : il peut mener ses traitements en parallèle
Une nouvelle notion 
1)Un stream ne porte pas de donnée 
2)Un stream ne peut pas modifier sa source 
3)Une source peut être infinie, ou non bornée 
On a donc besoin de garantir que les calculs seront menés en temps fini
Une nouvelle notion 
1)Un stream ne porte pas de donnée 
2)Un stream ne peut pas modifier sa source 
3)Une source peut être infinie, ou non bornée 
4)Un Stream traite ses données de façon lazy 
On peut optimiser les opérations entre elles 
On a besoin d’un mécanisme pour déclencher les traitements
Comment construire un Stream ? 
De nombreuses façons de faire… 
1)À partir d’une collection : 
Collection<String> collection = ... ; 
Stream<String> stream = collection.stream() ;
Comment construire un Stream ? 
De nombreuses façons de faire… 
1)À partir d’une collection : 
2)À partir d’un tableau : 
Stream<String> stream2 = 
Arrays.stream(new String [] {"one", "two", "three"}) ;
Comment construire un Stream ? 
De nombreuses façons de faire… 
1)À partir d’une collection : 
2)À partir d’un tableau : 
3)À partir des méthodes factory de Stream 
Stream<String> stream1 = Stream.of("one", "two", "three") ;
Comment construire un Stream ? 
Encore quelques patterns : 
Stream.empty() ; // Stream vide 
Stream.of(T t) ; // un seul élément 
Stream.generate(Supplier<T> s) ; 
Stream.iterate(T seed, UnaryOperator<T> f) ;
Comment construire un Stream ? 
Encore d’autres façons : 
string.chars() ; // retourne un IntStream 
lineNumberReader.lines() ; // retourne un Stream<String> 
random.ints() ; // retourne un IntStream
Deux types d’opérations 
On peut donc déclarer des opérations sur un Stream 
Deux types d’opérations : 
1)Les opérations intermédiaires 
Exemple : map, filter
Deux types d’opérations 
On peut donc déclarer des opérations sur un Stream 
Deux types d’opérations : 
1)Les opérations intermédiaires 
Exemple : map, filter 
2)Les opérations terminales, qui déclenchent le traitement 
Exemple : reduce
Un premier exemple 
Retour sur notre map / filter / reduce 
// map / filter / reduce pattern on collections 
int sum = persons.stream() 
.map(p -> p.getAge()) 
.filter(a -> a > 20) 
.reduce(0, (a1, a2) -> a1 + a2) ; 
Construction d’un Stream sur une List
Un premier exemple 
Retour sur notre map / filter / reduce 
// map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ; 
Déclarations
Un premier exemple 
Retour sur notre map / filter / reduce 
// map / filter / reduce pattern on collections 
int sum = persons.stream() 
.map(p -> p.getAge()) 
.filter(a -> a > 20) 
.reduce(0, (a1, a2) -> a1 + a2) ; 
On lance le calcul
Un premier exemple 
Retour sur notre map / filter / reduce 
// map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ; 
Valeur par défaut, dans le cas d’un stream vide
Un Stream possède un état 
Les implémentations de Stream possèdent un état : 
-SIZED = le cardinal du Stream est connu 
-ORDERED = l’ordre du Stream est important (List) 
-DISTINCT = pas de doublon dans le Stream (Set) 
-SORTED = les Stream est trié (SortedSet)
Un Stream possède un état 
Certaines opérations changent cet état 
-le filtrage annule SIZED 
-le mapping annule DISTINCT et SORTED
Un Stream possède un état 
Et cela permet d’optimiser ! 
-un HashSet ne peut pas avoir de doublons…
Un Stream possède un état 
Et cela permet d’optimiser ! 
-un HashSet ne peut pas avoir de doublons… 
-donc distinct() ne fait rien (NOP) pour un stream construit sur un HashSet
Un Stream possède un état 
Et cela permet d’optimiser ! 
-un HashSet ne peut pas avoir de doublons… 
-donc distinct() ne fait rien (NOP) pour un stream construit sur un HashSet 
-un TreeSet est trié, donc…
Un Stream possède un état 
Et cela permet d’optimiser ! 
-un HashSet ne peut pas avoir de doublons… 
-donc distinct() ne fait rien (NOP) pour un stream construit sur un HashSet 
-un TreeSet est trié, donc… 
-sorted() ne fait rien pour un stream construit sur un TreeSet
Opérations stateless / statefull 
Opérations Stateless / statefull 
Certaines opérations sont stateless : 
Cela signifie que l’on n’a pas besoin de plus d’information que ce qui est contenu dans p 
persons.stream().map(p -> p.getAge()) ;
Opérations stateless / statefull 
Opérations Stateless / statefull 
Certaines opérations sont stateless : 
Pas le cas de toutes les opérations 
persons.stream().map(p -> p.getAge()) ; 
stream.limit(10_000_000) ; // sélection des premiers 10M éléments
Exemple 
Trions un tableau de String 
Random rand = new Random() ; 
String [] strings = new String[10_000_000] ; 
for (int i = 0 ; i < strings.length ; i++) { 
strings[i] = Long.toHexString(rand.nextLong()) ; 
}
Exemple 
Trions un tableau de String 
Soooo Java 7… 
Random rand = new Random() ; 
String [] strings = new String[10_000_000] ; 
for (int i = 0 ; i < strings.length ; i++) { 
strings[i] = Long.toHexString(rand.nextLong()) ; 
}
Exemple 
Trions un tableau de String 
Meilleur ? 
Random rand = new Random() ; Stream<String> stream = Stream.generate( () -> Long.toHexString(rand.nextLong()) ) ;
Exemple 
Trions un tableau de String 
Meilleur ! 
// Random rand = new Random() ; Stream<String> stream = Stream.generate( () -> Long.toHexString(ThreadLocalRandom.current().nextLong()) ) ;
Exemple 
Trions un tableau de String 
// other way Stream<String> stream = ThreadLocalRandom .current() .longs() // returns a LongStream .mapToObj(l -> Long.toHexString(l)) ;
Exemple 
Trions un tableau de String 
// other way 
Stream<String> stream = 
ThreadLocalRandom 
.current() 
.longs() 
.mapToObj(Long::toHexString) ;
Exemple 
Trions un tableau de String 
// other way 
Stream<String> stream = 
ThreadLocalRandom 
.current() 
.longs() 
.mapToObj(Long::toHexString) 
.limit(10_000_000) 
.sorted() ; 
T = 4 ms
Exemple 
Trions un tableau de String 
// other way 
Stream<String> stream = 
ThreadLocalRandom 
.current() 
.longs() 
.mapToObj(Long::toHexString) 
.limit(10_000_000) 
.sorted() ; 
Object [] sorted = stream.toArray() ;
Exemple 
Trions un tableau de String 
// other way 
Stream<String> stream = 
ThreadLocalRandom 
.current() 
.longs() 
.mapToObj(Long::toHexString) 
.limit(10_000_000) 
.sorted() ; 
Object [] sorted = stream.toArray() ; 
T = 14 s
Exemple 
Trions un tableau de String 
// other way 
Stream<String> stream = 
ThreadLocalRandom 
.current() 
.longs() 
.mapToObj(Long::toHexString) 
.limit(10_000_000) 
.sorted() ; 
Object [] sorted = stream.toArray() ; 
T = 14 s 
Opérations intermédiaires !
Au final 
1)Il y a des opérations intermédiaires, et des opérations terminales 
2)Seule une opération terminale déclenche les traitements
Au final 
1)Il y a des opérations intermédiaires, et des opérations terminales 
2)Seule une opération terminale déclenche les traitements 
3)Une seule opération terminale est autorisée 
4)Un Stream ne peut traité qu’une seule fois 
Si besoin, un autre Stream doit être construit
Parallel Streams
Optimisation 
La première optimisation (après l’exécution lazy) est le parallélisme 
Fork / join permet la programmation parallèle depuis le JDK 7 
Écrire du code parallèle reste complexe, et ne mène pas toujours à de meilleures performances
Optimisation 
La première optimisation (après l’exécution lazy) est le parallélisme 
Fork / join permet la programmation parallèle depuis le JDK 7 
Écrire du code parallèle reste complexe, et ne mène pas toujours à de meilleures performances 
Utiliser l’API Stream est plus simple et plus sûr
Construction d’un Stream parallèle 
Deux patterns 
1)Appeler parallelStream() au lieu de stream() 
2)Appeler parallel() sur un stream existant 
Stream<String> s = strings.parallelStream() ; 
Stream<String> s = strings.stream().parallel() ;
Paralléliser est-il aussi simple ? 
En fait oui !
Paralléliser est-il aussi simple ? 
En fait oui ! 
… et non…
Paralléliser est-il aussi simple ? 
Exemple 1 : 
« retourne les premiers 10M éléments » 
persons.stream().limit(10_000_000) ;
Paralléliser est-il aussi simple ? 
Exemple 1 : performances 
Code 1 
List<Long> list = new ArrayList<>(10_000_100) ; 
for (int i = 0 ; i < 10_000_000 ; i++) { 
list1.add(ThreadLocalRandom.current().nextLong()) ; 
}
Paralléliser est-il aussi simple ? 
Exemple 1 : performances 
Code 2 
Stream<Long> stream = Stream.generate(() -> ThreadLocalRandom.current().nextLong()) ; List<Long> list1 = stream.limit(10_000_000).collect(Collectors.toList()) ;
Paralléliser est-il aussi simple ? 
Exemple 1 : performances 
Code 3 
Stream<Long> stream = ThreadLocalRandom.current().longs(10_000_000).mapToObj(Long::new) ; 
List<Long> list = stream.collect(Collectors.toList()) ;
Paralléliser est-il aussi simple ? 
Exemple 1 : performances 
Série 
Parallèle 
Code 1 (for) 
270 ms 
Code 2 (limit) 
310 ms 
Code 3 (longs) 
250 ms
Paralléliser est-il aussi simple ? 
Exemple 1 : performances 
Série 
Parallèle 
Code 1 (for) 
270 ms 
Code 2 (limit) 
310 ms 
500 ms 
Code 3 (longs) 
250 ms 
320 ms
Parallélisme 
Le parallélisme implique des calculs supplémentaires la plupart du temps 
Des opérations mal configurées vont entraîner des calculs inutiles, qui vont affaiblir les performances globales 
Exemple : un stream ORDERED est plus complexe à traiter
Réductions
La réduction simple 
La somme des âges 
// map / filter / reduce 
int sum = persons.stream() 
.map(p -> p.getAge()) 
.filter(a -> a > 20) 
.reduce(0, (a1, a2) -> a1 + a2) ;
La réduction simple 
Ca serait bien de pouvoir écrire : 
Mais sum() n’est pas définie sur Stream<T> 
Que voudrait dire « additionner des personnes » ? 
// map / filter / reduce int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .sum() ;
La réduction simple 
Ca serait bien de pouvoir écrire : 
Mais sum() n’est pas définie sur Stream<T> 
Mais il y a une méthode sum() sur IntStream ! 
// map / filter / reduce 
int sum = persons.stream() 
.map(p -> p.getAge()) 
.filter(a -> a > 20) 
.sum() ;
La réduction simple 
2ème version : 
Résultat pour une liste vide : 0 
// map / filter / reduce 
int sum = persons.stream() 
.map(Person::getAge) 
.filter(a -> a > 20) 
.mapToInt(Integer::intValue) 
.sum() ;
La réduction simple 
2ème version (encore meilleure) : 
Résultat pour une liste vide : 0 
// map / filter / reduce 
int sum = persons.stream() 
.mapToInt(Person::getAge) 
.filter(a -> a > 20) 
// .mapToInt(Integer::intValue) 
.sum() ;
La réduction simple 
Qu’en est-il de min() et de max() ? 
Quelle valeur par défaut pour max() ? 
// map / filter / reduce 
....... = persons.stream() 
.mapToInt(Person::getAge) 
.filter(a -> a > 20) 
.max() ;
Problème des valeurs par défaut 
La notion de « valeur par défaut » est plus complexe qu’il y paraît…
Problème des valeurs par défaut 
La notion de « valeur par défaut » est plus complexe qu’il y paraît… 
1)La « valeur par défaut » est la réduction de l’ensemble vide
Problème des valeurs par défaut 
La notion de « valeur par défaut » est plus complexe qu’il y paraît… 
1)La « valeur par défaut » est la réduction de l’ensemble vide 
2)Mais aussi l’élément neutre de la réduction
Problème des valeurs par défaut 
Problème : max() and min() n’ont pas d’élément neutre 
ie : un élément e pour lequel max(e, a) = a
Problème des valeurs par défaut 
Problème : max() and min() n’ont pas d’élément neutre 
ie : un élément e pour lequel max(e, a) = a 
Ca ne peut pas être 0 : max(-1, 0) = 0 
−∞ n’est pas un entier
Problème des valeurs par défaut 
Donc quelle est la valeur par défaut de max() et min() ?
Problème des valeurs par défaut 
Donc quelle est la valeur par défaut de max() et min() ? 
Réponse : il n’y a pas de valeur par défaut pour max() et pour min()
Problème des valeurs par défaut 
Donc quel type choisir pour la méthode max() ? 
// map / filter / reduce pattern on collections 
....... = persons.stream() 
.mapToInt(Person::getAge) 
.filter(a -> a > 20) 
.max() ;
Problème des valeurs par défaut 
Donc quel type choisir pour la méthode max() ? 
Si c’est int, la valeur par défaut sera 0… 
// map / filter / reduce pattern on collections 
....... = persons.stream() 
.mapToInt(Person::getAge) 
.filter(a -> a > 20) 
.max() ;
Optionals 
Sans valeur par défaut, il faut trouver autre chose… 
// map / filter / reduce pattern on collections 
OptionalInt optionalMax = persons.stream() 
.mapToInt(Person::getAge) 
.filter(a -> a > 20) 
.max() ; 
« il peut ne pas y avoir de résultat »
Optionals 
Que peut-on faire avec OptionalInt ? 
1er pattern : tester s’il contient une valeur 
OptionalInt optionalMax = ... ; 
int max ; 
if (optionalMax.isPresent()) { 
max = optionalMax.get() ; 
} else { 
max = ... ; // décider d’une « valeur par défaut » 
}
Optionals 
Que peut-on faire avec OptionalInt ? 
2ème pattern : lire la valeur ou jeter une exception 
OptionalInt optionalMax = ... ; 
// throws NoSuchElementException if no held value 
int max = optionalMax.getAsInt() ;
Optionals 
Que peut-on faire avec OptionalInt ? 
3ème pattern : lire la valeur / retourner une valeur par défaut 
OptionalInt optionalMax = ... ; 
// get 0 if no held value 
int max = optionalMax.orElse(0) ;
Optionals 
Que peut-on faire avec OptionalInt ? 
4ème pattern : lire la valeur ou jeter une exception 
OptionalInt optionalMax = ... ; 
// exceptionSupplier will supply an exception, if no held value 
int max = optionalMax.orElseThrow(exceptionSupplier) ;
Available Optionals 
Optional<T> 
OptionalInt, OptionalLong, OptionalDouble
Réductions disponibles 
Sur Stream<T> : 
-reduce() 
-count(), min(), max() 
-anyMatch(), allMatch(), noneMatch() 
-findFirst(), findAny() 
-toArray() 
-forEach(), forEachOrdered()
Réductions disponibles 
Sur IntStream, LongStream, DoubleStream : 
-average() 
-sum() 
-summaryStatistics()
Mutable reductions
Mutable reductions : exemple 1 
Utilisation d’une classe helper : Collectors 
ArrayList<String> strings = 
stream 
.map(Object::toString) 
.collect(Collectors.toList()) ;
Mutable reductions : exemple 2 
Concaténation de String avec un helper 
String names = persons 
.stream() 
.map(Person::getName) 
.collect(Collectors.joining()) ;
Mutable reductions 
Une réduction mutable dépend : 
-d’un container : Collection or StringBuilder 
-d’un moyen d’ajouter un élément au container 
-d’un moyen de fusionner deux containers (utilisé dans les opérations parallèles)
Collectors
La classe Collectors 
Une boite à outils (37 méthodes) pour la plupart des types de réduction 
-counting, minBy, maxBy 
-summing, averaging, summarizing 
-joining 
-toList, toSet, toMap 
Et 
- mapping, groupingBy, partionningBy
La classe Collectors 
Average, Sum, Count 
persons 
.stream() 
.collect(Collectors.averagingDouble(Person::getAge)) ; 
persons .stream() .collect(Collectors.counting()) ;
La classe Collectors 
Concaténation des noms dans une String 
String names = persons 
.stream() 
.map(Person::getName) 
.collect(Collectors.joining(", ")) ;
La classe Collectors 
Accumulation dans un Set 
Set<Person> setOfPersons = persons 
.stream() 
.collect( 
Collectors.toSet()) ;
La classe Collectors 
Accumulation dans une collection passée en paramètre 
TreeSet<Person> treeSetOfPersons = persons .stream() .collect( Collectors.toCollection(TreeSet::new)) ;
La classe Collectors 
Calculer un max avec un comparateur 
Bonus : une API Comparator 
Optional<Person> optionalPerson = persons 
.stream() 
.collect( 
Collectors.maxBy( 
Comparator.comparing(Person::getAge)) ;
Construction de comparateurs 
Nouvelle API pour construire des comparateurs 
Comparator<Person> comp = 
Comparator.comparing(Person::getLastName) 
.thenComparing(Person::getFirstName) 
.thenComparing(Person::getAge) ;
Classe Collectors : mapping 
La méthode mapping() prend 2 paramètres 
-une fonction, qui mappe les éléments du Stream 
-un collecteur, appelé « downstream », appliqué aux valeurs mappées
Classe Collectors : mapping 
Accumuler les noms des personnes dans un Set 
Set<String> set = persons 
.stream() 
.collect( 
Collectors.mapping( 
Person::getLastName, 
Collectors.toSet())) ;
Classe Collectors : mapping 
Mapper le stream, accumulation dans une collection 
TreeSet<String> set = persons 
.stream() 
.collect( 
Collectors.mapping( 
Person::getLastName, 
Collectors.toCollection(TreeSet::new)) 
) ;
Classe Collectors : groupingBy 
« Grouping by » construit des tables de hachage 
-méthode de construction des clés 
-par défaut les éléments sont rangés dans une liste 
-on peut spécifier un downstream (collector)
Classe Collectors : groupingBy 
Des personnes par âge 
Map<Integer, List<Person>> map = 
persons 
.stream() 
.collect( 
Collectors.groupingBy( 
Person::getAge)) ;
Classe Collectors : groupingBy 
… rangées dans des Set 
Map<Integer, Set<Person>> map = 
persons 
.stream() 
.collect( 
Collectors.groupingBy( 
Person::getAge, 
Collectors.toSet() // le downstream 
) ;
Classe Collectors : groupingBy 
… on ne garde que les noms 
Map<Integer, Set<String>> map = 
persons 
.stream() 
.collect( 
Collectors.groupingBy( 
Person::getAge, 
Collectors.mapping( // 
Person::getLastName, // the downstream 
Collectors.toSet() // 
) 
) ;
Classe Collectors : groupingBy 
… les noms rangés dans des TreeSet 
Map<Integer, TreeSet<String>> map = 
persons 
.stream() 
.collect( 
Collectors.groupingBy( 
Person::getAge, 
Collectors.mapping( 
Person::getLastName, 
Collectors.toCollection(TreeSet::new) 
) 
) ;
Classe Collectors : groupingBy 
… etc… etc… etc… 
TreeMap<Integer, TreeSet<String>> map = 
persons 
.stream() 
.collect( 
Collectors.groupingBy( 
Person::getAge, 
TreeMap::new, 
Collectors.mapping( 
Person::getLastName, 
Collectors.toCollection(TreeSet::new) 
) 
) ;
Classe Collectors : groupingBy 
Exemple : création d’un histogramme des âges 
Donne le nombre de personnes par âge 
Map<Integer, Long> map = 
persons 
.stream() 
.collect( 
Collectors.groupingBy( 
Person::getAge, 
Collectors.counting() 
) 
) ;
Classe Collectors : partionningBy 
Crée une Map<Boolean, …> à partir d’un prédicat 
-la table a deux clés : TRUE et FALSE 
-et on peut y ajouter un downstream
Classe Collectors : partionningBy 
Crée une Map<Boolean, …> avec un prédicat 
map.get(TRUE) retourne la liste des personnes de plus de 20 ans 
Map<Boolean, List<Person>> map = 
persons 
.stream() 
.collect( 
Collectors.partitioningBy(p -> p.getAge() > 20) 
) ;
Classe Collectors : partionningBy 
On peut définir d’autres traitements 
Map<Boolean, TreeSet<String>> map = 
persons 
.stream() 
.collect( 
Collectors.partitioningBy( 
p -> p.getAge() > 20, 
Collectors.mapping( 
Person::getLastName, 
Collectors.toCollection(TreeSet::new)) 
) 
) 
) ;
Classe Collectors : collectingAndThen 
Collecte les données avec un downstream 
Applique enfin une fonction appelée « finisher » 
Indispensable pour retourner des collections immutables
Classe Collectors : collectingAndThen 
Dans ce cas « Map::entrySet » est un finisher 
Set<Map.Entry<Integer, List<Person>>> set = 
persons 
.stream() 
.collect( 
Collectors.collectingAndThen( 
Collectors.groupingBy( 
Person::getAge), // downstream, construit une map 
Map::entrySet // finisher, appliqué à la map 
) ;
Quelques exemples réels
1er exemple 
Optional<Entry<Integer, Long>> opt = 
movies.stream().parallel() 
.collect( 
Collectors.collectingAndThen( 
Collectors.groupingBy( 
movie -> movie.releaseYear(), 
Collectors.counting() 
), 
Map::entrySet 
) 
) 
.stream() 
.max(Map.Entry.comparingByValue()) ;
1er exemple 
Optional<Entry<Integer, Long>> opt = 
movies.stream().parallel() 
.collect( 
Collectors.collectingAndThen( 
Collectors.groupingBy( 
movie -> movie.releaseYear(), 
Collectors.counting() 
), 
Map::entrySet 
) 
) 
.stream() 
.max(Map.Entry.comparingByValue()) ; 
Un stream de movies
1er exemple 
Optional<Entry<Integer, Long>> opt = 
movies.stream().parallel() 
.collect( 
Collectors.collectingAndThen( 
Collectors.groupingBy( 
movie -> movie.releaseYear(), 
Collectors.counting() 
), 
Map::entrySet 
) 
) 
.stream() 
.max(Map.Entry.comparingByValue()) ; 
Construction d’une map année / # de films
1er exemple 
Optional<Entry<Integer, Long>> opt = 
movies.stream().parallel() 
.collect( 
Collectors.collectingAndThen( 
Collectors.groupingBy( 
movie -> movie.releaseYear(), 
Collectors.counting() 
), 
Map::entrySet 
) 
) 
.stream() 
.max(Map.Entry.comparingByValue()) ; 
Construction de l’EntrySet
1er exemple 
Optional<Entry<Integer, Long>> opt = 
movies.stream().parallel() 
.collect( 
Collectors.collectingAndThen( 
Collectors.groupingBy( 
movie -> movie.releaseYear(), 
Collectors.counting() 
), 
Map::entrySet 
) 
) 
.stream() 
.max(Map.Entry.comparingByValue()) ; 
Et déterminer la plus grande valeur
1er exemple 
Optional<Entry<Integer, Long>> opt = 
movies.stream().parallel() 
.collect( 
Collectors.collectingAndThen( 
Collectors.groupingBy( 
movie -> movie.releaseYear(), 
Collectors.counting() 
), 
Map::entrySet 
) 
) 
.stream() 
.max(Map.Entry.comparingByValue()) ; 
Retourne l’année qui a vu le plus grand nombre de films
Conclusion
Conclusion 
Pourquoi les lambdas ont-ils été introduits dans Java 8 ?
Conclusion 
Pourquoi les lambdas ont-ils été introduits dans Java 8 ? 
Réponse : parce que c’est à la mode !
Conclusion 
Pourquoi les lambdas ont-ils été introduits dans Java 8 ? 
Réponse : parce que c’est à la mode !
Conclusion 
Pourquoi les lambdas ont-ils été introduits dans Java 8 ? 
Réponse : parce que c’est à la mode ! 
Parce que le code écrit est plus compact !
Plus c’est court, plus c’est bon ! 
Un exemple de code compact 
#include "stdio.h" 
main() { 
int b=0,c=0,q=60,_=q;for(float i=-20,o,O=0,l=0,j,p;j=O*O,p=l*l, 
(!_--|(j+p>4)?fputc(b?q+(_/3):10,(i+=!b,p=j=O=l=0,c++,stdout)), 
_=q:l=2*O*l+i/20,O=j-p+o),b=c%q,c<2400;o=-2+b*.05) ; 
} 
http://www.codeproject.com/Articles/2228/Obfuscating-your-Mandelbrot-code
Un exemple de code compact 
#include "stdio.h" 
main() { 
int b=0,c=0,q=60,_=q;for(float i=-20,o,O=0,l=0,j,p;j=O*O,p=l*l, 
(!_--|(j+p>4)?fputc(b?q+(_/3):10,(i+=!b,p=j=O=l=0,c++,stdout)), 
_=q:l=2*O*l+i/20,O=j-p+o),b=c%q,c<2400;o=-2+b*.05) ; 
} 
http://www.codeproject.com/Articles/2228/Obfuscating-your-Mandelbrot-code 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
++++++++++++++++++++++++++++++++++++ ++ +++++++++++ 
+++++++++++++++++++++++++++++++++++ +++++++ 
++++++++++++++++++++++++++++++++++++ +++++++ 
+++++++++++++++++++++++++++++++++++ ++++++++ 
++++++++++++++++++++++++++++++++++ +++++++ 
+++++++++++++++++++++++++++++++++ +++++ 
+++++++++++++++++++++++++++++++++ ++++++ 
+++++++++++++++++++++++ + +++++ ++++++ 
+++++++++++++++++++++++ ++ ++++++ 
++++++++++++++++++++++ + ++++++ 
++++++++++++++++++++++ + ++++++ 
++++++++++++++++++++ + + +++++++ 
++++++ ++++++++ 
++++++++++++++++++++ + + +++++++ 
++++++++++++++++++++++ + ++++++ 
++++++++++++++++++++++ + ++++++ 
+++++++++++++++++++++++ ++ ++++++ 
+++++++++++++++++++++++ + +++++ ++++++ 
+++++++++++++++++++++++++++++++++ ++++++ 
+++++++++++++++++++++++++++++++++ +++++ 
++++++++++++++++++++++++++++++++++ +++++++ 
+++++++++++++++++++++++++++++++++++ ++++++++ 
++++++++++++++++++++++++++++++++++++ +++++++ 
+++++++++++++++++++++++++++++++++++ +++++++ 
++++++++++++++++++++++++++++++++++++ ++ +++++++++++ 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
Plus c’est court, plus c’est bon !
Conclusion 
Pourquoi les lambdas ont-ils été introduits dans Java 8 ? 
Réponse : parce que c’est à la mode ! 
Parce que le code écrit est plus compact !
Conclusion 
Pourquoi les lambdas ont-ils été introduits dans Java 8 ? 
Parce que les lambdas autorisent des nouveaux patterns qui permettent de paralléliser les traitements simplement et de façon sûre 
-dont les applications ont besoin 
-dont concepteurs d’API ont besoin
Conclusion 
Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe
Conclusion 
Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe 
Migrer vers Java 8 va nécessiter du travail pour nous les développeurs 
-auto-formation 
-changement de nos habitudes de programmer
Conclusion 
Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe 
Migrer vers Java 8 va nécessiter du travail pour nous les développeurs 
-auto-formation 
-changement de nos habitudes de programmer 
-convaincre nos boss…
Conclusion 
Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe 
Téléchargeons la version développeur sur openjdk.net 
Date de sortie : 18 mars 2014
Conclusion 
Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe 
« Java is a blue collar language. It’s not PhD thesis material but a language for a job » – James Gosling, 1997
Conclusion 
Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe 
« Language features are not a goal unto themselves; language features are enablers, encouraging or discouraging certain styles and idioms » – Brian Goetz, 2013
Conclusion 
Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe 
La bonne nouvelle : Java est toujours Java !
20140123 java8 lambdas_jose-paumard-soat
20140123 java8 lambdas_jose-paumard-soat

Contenu connexe

Tendances

201303 - Java8
201303 - Java8201303 - Java8
201303 - Java8
lyonjug
 

Tendances (20)

Les Streams sont parmi nous
Les Streams sont parmi nousLes Streams sont parmi nous
Les Streams sont parmi nous
 
De java à swift en 2 temps trois mouvements
De java à swift en 2 temps trois mouvementsDe java à swift en 2 temps trois mouvements
De java à swift en 2 temps trois mouvements
 
Programmation Fonctionnelle
Programmation FonctionnelleProgrammation Fonctionnelle
Programmation Fonctionnelle
 
Programmation fonctionnelle
Programmation fonctionnelleProgrammation fonctionnelle
Programmation fonctionnelle
 
API Asynchrones en Java 8
API Asynchrones en Java 8API Asynchrones en Java 8
API Asynchrones en Java 8
 
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
 
Java (8) eXperiments - DevoxxFR 2016
Java (8) eXperiments - DevoxxFR 2016Java (8) eXperiments - DevoxxFR 2016
Java (8) eXperiments - DevoxxFR 2016
 
Chapitre8: Collections et Enumerations En Java
Chapitre8: Collections et Enumerations En JavaChapitre8: Collections et Enumerations En Java
Chapitre8: Collections et Enumerations En Java
 
ArrayList et LinkedList sont dans un bateau
ArrayList et LinkedList sont dans un bateauArrayList et LinkedList sont dans un bateau
ArrayList et LinkedList sont dans un bateau
 
Développement informatique : Algorithmique I : Récursion et arbre
Développement informatique : Algorithmique I : Récursion et arbreDéveloppement informatique : Algorithmique I : Récursion et arbre
Développement informatique : Algorithmique I : Récursion et arbre
 
Python avancé : Tuple et objet
Python avancé : Tuple et objetPython avancé : Tuple et objet
Python avancé : Tuple et objet
 
Type abstrait de données
Type abstrait de donnéesType abstrait de données
Type abstrait de données
 
Initiation r
Initiation rInitiation r
Initiation r
 
Librairies Java qui changent la vie
Librairies Java qui changent la vieLibrairies Java qui changent la vie
Librairies Java qui changent la vie
 
Python For Data Science - French Course
Python For Data Science - French CoursePython For Data Science - French Course
Python For Data Science - French Course
 
Introduction Clojure - Geneva JUG - Octobre 2012
Introduction Clojure - Geneva JUG - Octobre 2012Introduction Clojure - Geneva JUG - Octobre 2012
Introduction Clojure - Geneva JUG - Octobre 2012
 
Arbre et algorithme de recherche
Arbre et algorithme de rechercheArbre et algorithme de recherche
Arbre et algorithme de recherche
 
201303 - Java8
201303 - Java8201303 - Java8
201303 - Java8
 
Monitoring d'applications/environnements PHP: APM et Pinba
Monitoring d'applications/environnements PHP: APM et PinbaMonitoring d'applications/environnements PHP: APM et Pinba
Monitoring d'applications/environnements PHP: APM et Pinba
 
Python avancé : Ensemble, dictionnaire et base de données
Python avancé : Ensemble, dictionnaire et base de donnéesPython avancé : Ensemble, dictionnaire et base de données
Python avancé : Ensemble, dictionnaire et base de données
 

En vedette

Playtests, traductions, et relectures
Playtests, traductions, et relectures  Playtests, traductions, et relectures
Playtests, traductions, et relectures
Pascal Minoche
 
062112 french(eeoc response)
062112 french(eeoc response)062112 french(eeoc response)
062112 french(eeoc response)
VogelDenise
 
Dossier presentation bd reseau styx
Dossier presentation bd reseau styxDossier presentation bd reseau styx
Dossier presentation bd reseau styx
Pascal Minoche
 
Phenix de Saigon La Carte
Phenix de Saigon La CartePhenix de Saigon La Carte
Phenix de Saigon La Carte
sarounette50
 
Plan de-prevention-des-risques-argile-quel-impact-pour-les-assures
Plan de-prevention-des-risques-argile-quel-impact-pour-les-assuresPlan de-prevention-des-risques-argile-quel-impact-pour-les-assures
Plan de-prevention-des-risques-argile-quel-impact-pour-les-assures
Marcarazi
 
Projet de carrière
Projet de carrière Projet de carrière
Projet de carrière
cat_rioux
 
Ht lemagicienbet
Ht lemagicienbetHt lemagicienbet
Ht lemagicienbet
kelticman
 
Présentationrestauration de tableaux
Présentationrestauration de tableauxPrésentationrestauration de tableaux
Présentationrestauration de tableaux
atelierdesquen
 

En vedette (19)

Présentation ID-Stats
Présentation ID-StatsPrésentation ID-Stats
Présentation ID-Stats
 
Playtests, traductions, et relectures
Playtests, traductions, et relectures  Playtests, traductions, et relectures
Playtests, traductions, et relectures
 
Advertisement notes
Advertisement notesAdvertisement notes
Advertisement notes
 
Comput training
Comput trainingComput training
Comput training
 
Carrieres
CarrieresCarrieres
Carrieres
 
062112 french(eeoc response)
062112 french(eeoc response)062112 french(eeoc response)
062112 french(eeoc response)
 
Dossier presentation bd reseau styx
Dossier presentation bd reseau styxDossier presentation bd reseau styx
Dossier presentation bd reseau styx
 
title
titletitle
title
 
Apprentissage des langues en ligne et humanités numériques : une mise en équa...
Apprentissage des langues en ligne et humanités numériques : une mise en équa...Apprentissage des langues en ligne et humanités numériques : une mise en équa...
Apprentissage des langues en ligne et humanités numériques : une mise en équa...
 
Louaize pres antoine rajeh w
Louaize pres antoine rajeh wLouaize pres antoine rajeh w
Louaize pres antoine rajeh w
 
Phenix de Saigon La Carte
Phenix de Saigon La CartePhenix de Saigon La Carte
Phenix de Saigon La Carte
 
Wellscan entreprise - Masseo Concept
Wellscan entreprise - Masseo ConceptWellscan entreprise - Masseo Concept
Wellscan entreprise - Masseo Concept
 
Plan de-prevention-des-risques-argile-quel-impact-pour-les-assures
Plan de-prevention-des-risques-argile-quel-impact-pour-les-assuresPlan de-prevention-des-risques-argile-quel-impact-pour-les-assures
Plan de-prevention-des-risques-argile-quel-impact-pour-les-assures
 
title
titletitle
title
 
PARIS
PARISPARIS
PARIS
 
Présentation1
Présentation1Présentation1
Présentation1
 
Projet de carrière
Projet de carrière Projet de carrière
Projet de carrière
 
Ht lemagicienbet
Ht lemagicienbetHt lemagicienbet
Ht lemagicienbet
 
Présentationrestauration de tableaux
Présentationrestauration de tableauxPrésentationrestauration de tableaux
Présentationrestauration de tableaux
 

Similaire à 20140123 java8 lambdas_jose-paumard-soat

201305 - Lambda by R. Forax
201305 - Lambda by R. Forax201305 - Lambda by R. Forax
201305 - Lambda by R. Forax
lyonjug
 
Android Optimisations Greendroid
Android Optimisations GreendroidAndroid Optimisations Greendroid
Android Optimisations Greendroid
GDG Nantes
 

Similaire à 20140123 java8 lambdas_jose-paumard-soat (20)

Techday Arrow Group: Java 8
Techday Arrow Group: Java 8Techday Arrow Group: Java 8
Techday Arrow Group: Java 8
 
PL LSQL.pptx
PL LSQL.pptxPL LSQL.pptx
PL LSQL.pptx
 
201305 - Lambda by R. Forax
201305 - Lambda by R. Forax201305 - Lambda by R. Forax
201305 - Lambda by R. Forax
 
C# 7 - Nouveautés
C# 7 - NouveautésC# 7 - Nouveautés
C# 7 - Nouveautés
 
TAD (1).pptx
TAD (1).pptxTAD (1).pptx
TAD (1).pptx
 
Open close principle, on a dit étendre, pas extends !
Open close principle, on a dit étendre, pas extends !Open close principle, on a dit étendre, pas extends !
Open close principle, on a dit étendre, pas extends !
 
Chapitre 04 : les fonctions
Chapitre 04 : les fonctionsChapitre 04 : les fonctions
Chapitre 04 : les fonctions
 
La programmation fonctionnelle avec le langage OCaml
La programmation fonctionnelle avec le langage OCamlLa programmation fonctionnelle avec le langage OCaml
La programmation fonctionnelle avec le langage OCaml
 
SOLID _Principles.pptx
SOLID _Principles.pptxSOLID _Principles.pptx
SOLID _Principles.pptx
 
Partie1 TypeScript
Partie1 TypeScriptPartie1 TypeScript
Partie1 TypeScript
 
Cours de C++, en français, 2002 - Cours 2.1
Cours de C++, en français, 2002 - Cours 2.1Cours de C++, en français, 2002 - Cours 2.1
Cours de C++, en français, 2002 - Cours 2.1
 
Modèle de domaine riche dans une application métier complexe un exemple pratique
Modèle de domaine riche dans une application métier complexe un exemple pratiqueModèle de domaine riche dans une application métier complexe un exemple pratique
Modèle de domaine riche dans une application métier complexe un exemple pratique
 
Android Optimisations Greendroid
Android Optimisations GreendroidAndroid Optimisations Greendroid
Android Optimisations Greendroid
 
Développement informatique : Programmation fonctionnelle, décorateur et génér...
Développement informatique : Programmation fonctionnelle, décorateur et génér...Développement informatique : Programmation fonctionnelle, décorateur et génér...
Développement informatique : Programmation fonctionnelle, décorateur et génér...
 
Cours de C++ / Tronc commun deuxième année ISIMA
Cours de C++ / Tronc commun deuxième année ISIMACours de C++ / Tronc commun deuxième année ISIMA
Cours de C++ / Tronc commun deuxième année ISIMA
 
Chap1_Entrees_Sorties.pptx
Chap1_Entrees_Sorties.pptxChap1_Entrees_Sorties.pptx
Chap1_Entrees_Sorties.pptx
 
Chapitre6: Surcharge des opérateurs
Chapitre6:  Surcharge des opérateursChapitre6:  Surcharge des opérateurs
Chapitre6: Surcharge des opérateurs
 
Les fonctions lambdas en C++11 et C++14
Les fonctions lambdas en C++11 et C++14Les fonctions lambdas en C++11 et C++14
Les fonctions lambdas en C++11 et C++14
 
Theme 7
Theme 7Theme 7
Theme 7
 
syntax-matlab.pdf
syntax-matlab.pdfsyntax-matlab.pdf
syntax-matlab.pdf
 

Plus de SOAT

Soirée 3T Soat - Asp.net MVC
Soirée 3T Soat - Asp.net MVCSoirée 3T Soat - Asp.net MVC
Soirée 3T Soat - Asp.net MVC
SOAT
 

Plus de SOAT (20)

Back from Microsoft //Build 2018
Back from Microsoft //Build 2018Back from Microsoft //Build 2018
Back from Microsoft //Build 2018
 
L'entreprise libérée
L'entreprise libéréeL'entreprise libérée
L'entreprise libérée
 
Amélioration continue, c'est l'affaire de tous !
Amélioration continue, c'est l'affaire de tous !Amélioration continue, c'est l'affaire de tous !
Amélioration continue, c'est l'affaire de tous !
 
JAVA 8 : Migration et enjeux stratégiques en entreprise
JAVA 8 : Migration et enjeux stratégiques en entrepriseJAVA 8 : Migration et enjeux stratégiques en entreprise
JAVA 8 : Migration et enjeux stratégiques en entreprise
 
ARCHITECTURE MICROSERVICE : TOUR D’HORIZON DU CONCEPT ET BONNES PRATIQUES
ARCHITECTURE MICROSERVICE : TOUR D’HORIZON DU CONCEPT ET BONNES PRATIQUESARCHITECTURE MICROSERVICE : TOUR D’HORIZON DU CONCEPT ET BONNES PRATIQUES
ARCHITECTURE MICROSERVICE : TOUR D’HORIZON DU CONCEPT ET BONNES PRATIQUES
 
3/3 : The path to CDI 2.0 - Antoine Sabot-Durand
3/3 : The path to CDI 2.0 - Antoine Sabot-Durand3/3 : The path to CDI 2.0 - Antoine Sabot-Durand
3/3 : The path to CDI 2.0 - Antoine Sabot-Durand
 
1/3 : introduction to CDI - Antoine Sabot-Durand
1/3 : introduction to CDI - Antoine Sabot-Durand1/3 : introduction to CDI - Antoine Sabot-Durand
1/3 : introduction to CDI - Antoine Sabot-Durand
 
2/3 : CDI advanced - Antoine Sabot-Durand
2/3 : CDI advanced - Antoine Sabot-Durand2/3 : CDI advanced - Antoine Sabot-Durand
2/3 : CDI advanced - Antoine Sabot-Durand
 
Angular JS - Paterne Gaye-Guingnido
Angular JS - Paterne Gaye-Guingnido Angular JS - Paterne Gaye-Guingnido
Angular JS - Paterne Gaye-Guingnido
 
Dans l'enfer du Web Mobile - un retour d'expérience - Mathieu Parisot
Dans l'enfer du Web Mobile - un retour d'expérience - Mathieu ParisotDans l'enfer du Web Mobile - un retour d'expérience - Mathieu Parisot
Dans l'enfer du Web Mobile - un retour d'expérience - Mathieu Parisot
 
RxJava, Getting Started - David Wursteisen - 16 Octobre 2014
RxJava, Getting Started - David Wursteisen - 16 Octobre 2014RxJava, Getting Started - David Wursteisen - 16 Octobre 2014
RxJava, Getting Started - David Wursteisen - 16 Octobre 2014
 
L'impact du Responsive Web Design sur vos équipes projet - Mathieu Parisot - ...
L'impact du Responsive Web Design sur vos équipes projet - Mathieu Parisot - ...L'impact du Responsive Web Design sur vos équipes projet - Mathieu Parisot - ...
L'impact du Responsive Web Design sur vos équipes projet - Mathieu Parisot - ...
 
Nio sur Netty par Mouhcine Moulou - 3 avril 2014
Nio sur Netty par Mouhcine Moulou - 3 avril 2014Nio sur Netty par Mouhcine Moulou - 3 avril 2014
Nio sur Netty par Mouhcine Moulou - 3 avril 2014
 
Développer des applications iOS et Android avec c# grâce à Xamarin par Cyril ...
Développer des applications iOS et Android avec c# grâce à Xamarin par Cyril ...Développer des applications iOS et Android avec c# grâce à Xamarin par Cyril ...
Développer des applications iOS et Android avec c# grâce à Xamarin par Cyril ...
 
Amazon Web Service par Bertrand Lehurt - 11 mars 2014
Amazon Web Service par Bertrand Lehurt - 11 mars 2014Amazon Web Service par Bertrand Lehurt - 11 mars 2014
Amazon Web Service par Bertrand Lehurt - 11 mars 2014
 
ASP.Net Web API - Léonard Labat (18 février 2014)
ASP.Net Web API - Léonard Labat (18 février 2014)ASP.Net Web API - Léonard Labat (18 février 2014)
ASP.Net Web API - Léonard Labat (18 février 2014)
 
Xamarin et le développement natif d’applications Android, iOS et Windows en C#
 Xamarin et le développement natif d’applications Android, iOS et Windows en C# Xamarin et le développement natif d’applications Android, iOS et Windows en C#
Xamarin et le développement natif d’applications Android, iOS et Windows en C#
 
A la découverte du Responsive Web Design par Mathieu Parisot - Soat
A la découverte du Responsive Web Design par Mathieu Parisot - SoatA la découverte du Responsive Web Design par Mathieu Parisot - Soat
A la découverte du Responsive Web Design par Mathieu Parisot - Soat
 
MongoDB : la base NoSQL qui réinvente la gestion de données
MongoDB : la base NoSQL qui réinvente la gestion de donnéesMongoDB : la base NoSQL qui réinvente la gestion de données
MongoDB : la base NoSQL qui réinvente la gestion de données
 
Soirée 3T Soat - Asp.net MVC
Soirée 3T Soat - Asp.net MVCSoirée 3T Soat - Asp.net MVC
Soirée 3T Soat - Asp.net MVC
 

20140123 java8 lambdas_jose-paumard-soat

  • 1. JDK 8 & Lambdas Lambdas, Streams, Collectors
  • 2. Pourquoi ont-ils été introduits ?
  • 3. Pourquoi ont-ils été introduits ? Comment vont-ils changer nos habitudes de programmation ?
  • 4.
  • 6. Année d’édition 1994 En stock. Expédié et vendu par Amazon. Emballage cadeau disponible.
  • 7.
  • 8.
  • 9. Formation Java 8 6 & 7 février 2014 BBL
  • 10.
  • 12. Introduisons les lambdas sur un exemple simple
  • 13. Un exemple très simple public class Person { private String name ; private int age ; // constructors // getters / setters } List<Person> list = new ArrayList<>() ; Un bon vieux bean … et une bonne vieille liste
  • 14. int sum = 0 ; // I need a default value in case // the list is empty int average = 0 ; for (Person person : list) { sum += person.getAge() ; } if (!list.isEmpty()) { average = sum / list.size() ; } Calculons la moyenne des âges des personnes
  • 15. int sum = 0 ; int n = 0 ; int average = 0 ; for (Person person : list) { if (person.getAge() > 20) { n++ ; sum += person.getAge() ; } } if (n > 0) { average = sum / n ; } Plus dur : pour les personnes de plus de 20 ans
  • 16. « programmation impérative » int sum = 0 ; int n = 0 ; int average = 0 ; for (Person person : list) { if (person.getAge() > 20) { n++ ; sum += person.getAge() ; } } if (n > 0) { average = sum / n ; } Plus dur : pour les personnes de plus de 20 ans
  • 17. select avg(age) from Person where age > 20 … pas une obligation ! Ici on décrit le résultat
  • 18. select avg(age) from Person where age > 20 Dans ce cas la base de données mène le calcul comme elle l’entend © SQL 1974 … pas une obligation ! Ici on décrit le résultat
  • 19. Person age age > 20 sum 1ère étape : mapping map
  • 20. Mapping : -prend une liste d’un type donné -retourne une liste d’un autre type -possède le même nombre d’éléments 1ère étape : mapping map Person age age > 20 sum
  • 21. 2ème étape : filtrage filter map Person age age > 20 sum
  • 22. Filtrage : -prend une liste d’un type donné -retourne une liste du même type -mais avec moins d’éléments Person age age > 20 sum 2ème étape : filtrage filter map
  • 23. 3ème étape : réduction reduce filter map Person age age > 20 sum
  • 24. Reduction : agrégation des éléments d’une liste dans un seul élément Ex : moyenne, somme, min, max, etc… Person age age > 20 sum 3ème étape : réduction reduce filter map
  • 25. Comment peut-on modéliser ce traitement ?
  • 26. La façon JDK 7 On crée une interface pour modéliser le mapper… public interface Mapper<T, V> { public V map(T t) ; }
  • 27. Mapper<Person, Integer> mapper = new Mapper<Person, Integer>() { public Integer map(Person p) { return p.getAge() ; } } La façon JDK 7 … et on crée une classe anonyme public interface Mapper<T, V> { public V map(T t) ; }
  • 28. AgePredicate predicate = new Predicate<Integer>() { public boolean filter(Integer i) { return i > 20 ; } } public interface Predicate<T> { public boolean filter(T t) ; } La façon JDK 7 On peut faire la même chose pour le filtrage
  • 29. Reducer<Integer> reduction = new Reducer<Integer>() { public Integer reduce(Integer i1, Integer i2) { return i1 + i2 ; } } public interface Reducer<T> { public T reduce(T t1, T t2) ; } La façon JDK 7 Et enfin pour la réduction
  • 30. Au final, le pattern map / filter / reduce en JDK 7 : 1)Créer 3 interfaces public interface Mapper<T, V> { public V map(T t) ; } public interface Predicate<T> { public boolean filter(T t) ; } public interface Reducer<T> { public T reduce(T t1, T t2) ; } La façon JDK 7
  • 31. List<Person> persons = ... ; int sum = persons.map( new Mapper<Person, Integer>() { public Integer map(Person p) { return p.getAge() ; } }) .filter( new Filter<Integer>() { public boolean filter(Integer age) { return age > 20 ; } }) .reduce(0, new Reducer<Integer>() { public Integer recude(Integer i1, Integer i2) { return i1 + i2 ; } } }) ; La façon JDK 7 Au final, le pattern map / filter / reduce en JDK 7 : 1)Créer 3 interfaces 2)Et on applique…
  • 32. List<Person> persons = ... ; int sum = persons.map( new Mapper<Person, Integer>() { public Integer map(Person p) { return p.getAge() ; } }) .filter( new Filter<Integer>() { public boolean filter(Integer age) { return age > 20 ; } }) .reduce(0, new Reducer<Integer>() { public Integer recude(Integer i1, Integer i2) { return i1 + i2 ; } } }) ; La façon JDK 7 Au final, le pattern map / filter / reduce en JDK 7 : 1)Créer 3 interfaces 2)Et on applique…
  • 33. À la façon du JDK 8
  • 34. mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { return person.getAge() ; } } La façon du JDK 8 Prenons l’exemple du Mapper
  • 35. mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return person.getAge() ; } } Prenons l’exemple du Mapper La façon du JDK 8
  • 36. mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return p.getAge() ; } } mapper = (Person person) ; On prend person La façon du JDK 8 Prenons l’exemple du Mapper
  • 37. mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return person.getAge() ; } } mapper = (Person person) -> ; et… La façon du JDK 8 Prenons l’exemple du Mapper
  • 38. mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return person.getAge() ; } } mapper = (Person person) -> person.getAge() ; … on retourne son âge La façon du JDK 8 Prenons l’exemple du Mapper
  • 39. Prenons l’exemple du Mapper Le compilateur reconnaît cette expression comme une implémentation du mapper mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return person.getAge() ; } } mapper = (Person person) -> person.getAge() ; La façon du JDK 8
  • 40. Que se passe-t-il si … … il y a plus d’une ligne de code ? Accolades, un return explicite mapper = (Person person) -> { System.out.println("Mapping " + person) ; return person.getAge() ; }
  • 41. Que se passe-t-il si … …le type de retour est void ? consumer = (Person person) -> p.setAge(p.getAge() + 1) ;
  • 42. Que se passe-t-il si … …la méthode prend plus d’un argument ? Ou : reducer = (int i1, int i2) -> { return i1 + i2 ; } reducer = (int i1, int i2) -> i1 + i2 ;
  • 43. La façon du JDK 8 Comment le compilateur reconnaît-il l’implémentation du mapper ? mapper = (Person person) -> person.getAge() ;
  • 44. Comment le compilateur reconnaît-il l’implémentation du mapper ? 1)Il ne faut qu’une méthode dans le mapper 2)Les types des paramètres et le type de retour doivent être compatible 3)Les exceptions jetées doivent être compatibles mapper = (Person person) -> person.getAge() ; La façon du JDK 8
  • 45. D’autres lambdas On peut écrire d’autres lambdas facilement : mapper = (Person person) -> person.getAge() ; // mapper filter = (int age) -> age > 20 ; // filter reducer = (int i1, int i2) -> i1 + i2 ; // reducer
  • 46. Et la plupart du temps, le compilateur reconnaît ceci : Le type des paramètres peut être omis mapper = person -> person.getAge() ; // mapper filter = age -> age > 20 ; // filter reducer = (i1, i2) -> i1 + i2 ; // reducer D’autres lambdas
  • 47. Une remarque sur la réduction Comment cela fonctionne-t-il réellement ?
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57. Réduction 2 exemples : Attention : le résultat est toujours reproductible en série il ne l’est en général pas en parallèle Reducer r1 = (i1, i2) -> i1 + i2 ; // Ok Reducer r2 = (i1, i2) -> i1*i1 + i2*i2 ; // Oooops
  • 58. Pour le moment Une expression lambda est une autre façon d’écrire des instances de classes anonymes
  • 59. Il y a d’autres syntaxes On peut écrire : Mais on peut aussi écrire : mapper = person -> person.getAge() ; mapper = Person::getAge ; // méthode non statique
  • 60. Il y a d’autres syntaxes On peut écrire : Ou encore : sum = (i1, i2) -> i1 + i2 ; sum = Integer::sum ; // méthode statique, nouvelle ! max = (i1, i2) -> i1 > i2 ? i1 : i2 ; max = Integer::max ; // méthode statique, nouvelle !
  • 61. Il y a d’autres syntaxes Encore un autre exemple : toLower = String::toLowerCase ; // !!!! NON NON NON !!!! toLowerFR = String::toLowerCase(Locale.FRANCE) ;
  • 62. Plus loin sur les lambdas
  • 63. Questions : Comment modéliser une expression lambda ?
  • 64. Questions : Comment modéliser une expression lambda ? Puis-je mettre une expression lambda dans une variable ?
  • 65. Questions : Comment modéliser une expression lambda ? Puis-je mettre une expression lambda dans une variable ? Un lambda est-il un objet ?
  • 66. Modélisation Un lambda = instance d’une « interface fonctionnelle » @FunctionalInterface public interface Consumer<T> { public void accept(T t) ; }
  • 67. Modélisation Un lambda = instance d’une « interface fonctionnelle » - ne possède qu’une unique méthode @FunctionalInterface public interface Consumer<T> { public void accept(T t) ; }
  • 68. Modélisation Un lambda = instance d’une « interface fonctionnelle » - ne possède qu’une unique méthode - peut être annotée par @FunctionalInterface (optionnel) @FunctionalInterface public interface Consumer<T> { public void accept(T t) ; }
  • 69. Mettre un lambda dans une variable Exemple d’un consommateur : Consumer<String> c = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s) ; } } ; Consumer<String> c = s -> System.out.println(s) ; Donc :
  • 70. Questions : Quel modèle pour un lambda ? réponse : une interface fonctionnelle Puis-je mettre un lambda dans une variable ? réponse : oui Un lambda est-il un objet ?
  • 71. Un lambda est-il un objet ? Petit jeu des 7 erreurs (avec une seule erreur) Consumer<String> c = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s) ; } } ; Consumer<String> c = s -> System.out.println(s) ;
  • 72. Un lambda est-il un objet ? Petit jeu des 7 erreurs (avec une seule erreur) Consumer<String> c = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s) ; } } ; Consumer<String> c = s -> System.out.println(s) ;
  • 73. Questions : Quel modèle pour un lambda ? réponse : une interface fonctionnelle Puis-je mettre un lambda dans une variable ? réponse : oui Un lambda est-il un objet ? réponse : non
  • 74. Des lambdas à profusion : Java.util.functions
  • 75. Java.util.functions C’est dans ce package que sont les interfaces fonctionnelles Il y en a 43
  • 76. Java.util.functions Supplier Consumer / BiConsumer Function / BiFunction (UnaryOperator / BinaryOperator) Predicate / BiPredicate En plus des versions construites sur les types primitifs
  • 77. Supplier Un supplier fournit un objet public interface Supplier<T> { T get() ; }
  • 78. Consumer Un consommateur consomme un objet public interface Consumer<T> { void accept(T t) ; } Consumer<String> c1 = s -> System.out.println(s) ; Consumer<String> c2 = ... ; Consumer<String> c3 = c1.andThen(c2) ; persons.stream().forEach(c3) ;
  • 79. Function Une fonction prend un objet et retourne un autre objet Les fonctions peuvent être chaînées et / ou composées BiFunction prend deux arguments au lieu d’un UnaryOperator et BinaryOperator opèrent sur un seul type public interface Function<T, R> { R apply(T t) ; }
  • 80. Predicate Un Predicate prend un objet et retourne un booléen Il peut être inversé, et composé avec des AND ou OR public interface Predicate<T> { boolean test(T t) ; }
  • 81. Retour sur map / filter / reduce
  • 82. La façon JDK 7 Comment implémenter le pattern map / filter / reduce sur List<Person> ?
  • 83. Mapping d’une liste Mapping en JDK 8 avec des lambdas List<Person> persons = new ArrayList<>() ; List<Integer> ages = Lists.map( persons, person -> person.getAge() ) ;
  • 84. Mapping d’une liste Mapping en JDK 8 avec des lambdas List<Person> persons = new ArrayList<>() ; List<Integer> ages = Lists.map( persons, Person::getAge ) ;
  • 85. Pattern complet Le pattern va ressembler à ça : Pour : l’API peut être optimisée sans que l’on ait à toucher au code, super ! // pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;
  • 86. Pattern complet Le pattern va ressembler à ça : Pour : l’API peut être optimisée sans que l’on ait à toucher au code, super ! Contre… // pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;
  • 87. Pattern complet 1) Supposons que persons soit vraiment GRANDE // pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;
  • 88. Pattern complet 1) Supposons que persons soit vraiment GRANDE 2 duplications : ages & agesGT20 // pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;
  • 89. Pattern complet 1) Supposons que persons soit vraiment GRANDE 2 duplications : ages & agesGT20 Que fait-on de ces listes ? On les envoie au GC ! // pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;
  • 90. Pattern complet 2) Supposons que nous aillons un reducer : allMatch allMatch est vrai si tous les noms sont plus courts que 20 caractères Voyons une implémentation possible de allMatch() // pattern map / filter / reduce List<Person> persons = ... ; List<String> names = Lists.map(persons, p -> p.getName()) ; boolean allMatch = Lists.allMatch(names, n -> n.length() < 20) ;
  • 91. Écriture de allMatch() Voici une implémentation basique de allMatch() public static <T> boolean allMatch( List<? extends T> list, Filter<T> filter) { for (T t : list) { if (!filter.filter(t)) { return false ; } } return true ; } Pas besoin de parcourir toute la liste !
  • 92. Pattern complet Quand on applique la réduction allMatch()… … names a déjà été évaluée ! // pattern map / filter / reduce List<Person> persons = ... ; List<String> names = Lists.map(persons, p -> p.getName()) ; boolean allMatch = Lists.allMatch(names, n.length() < 20) ;
  • 93. Pattern complet Quand on applique la réduction allMatch()… … names a déjà été évaluée ! Il aurait fallu appliquer le mapping de façon lazy // pattern map / filter / reduce List<Person> persons = ... ; List<String> names = Lists.map(persons, p -> p.getName()) ; boolean allMatch = Lists.allMatch(names, n.length() < 20) ;
  • 94. Conclusion Pour : 1 Contre : 2 (au moins) // pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;
  • 95. // pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ; Conclusion Pour : 1 Contre : 2 (au moins)
  • 96. Conclusion Et il en va de même pour celui-ci : // pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = persons.map(p -> p.getAge()) ; List<Integer> agesGT20 = ages.filter(a -> a > 20) ; int sum = agesGT20.reduce(ages, (i1, i2) -> i1 + i2) ;
  • 97. Conclusion (again) On a besoin d’un nouveau concept pour traiter les listes de grande taille de façon efficace
  • 99. Introduction Implémenter le map / filter / reduce sur Collection aurait mené à ceci : Et même si cette approche n’est pas viable, c’est une façon agréable d’écrire les choses // map / filter / reduce pattern sur Collection int sum = persons .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;
  • 100. Introduction Conservons le même genre de pattern, en ajoutant un appel intermédiaire // map / filter / reduce pattern sur Collection int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;
  • 101. Introduction Collection.stream() retourne un Stream : une nouvelle interface Nouvelle interface = on a les mains libres ! // map / filter / reduce pattern sur Collection int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;
  • 102. Nouvelle interface Collection Donc on a besoin d’une nouvelle méthode sur Collection public interface Collection<E> { // nos bonnes vieilles méthodes Stream<E> stream() ; }
  • 103. Nouvelle interface Collection Problème : ArrayList ne compile plus… Une solution doit être trouvée ! public interface Collection<E> { // nos bonnes vieilles méthodes Stream<E> stream() ; }
  • 105. Interfaces Java 8 Problème : ajouter des méthodes à une interface sans toucher aux implémentations…
  • 106. Problème : ajouter des méthodes à une interface sans toucher aux implémentations… Solution : changer la façon dont les interfaces fonctionnent en Java ! Interfaces Java 8
  • 107. Interfaces Java 8 ArrayList a besoin de l’implémentation de stream()… public interface Collection<E> { // nos bonnes vieilles méthodes Stream<E> stream() ; }
  • 108. Interfaces Java 8 Solution : mettons-les dans l’interface ! public interface Collection<E> { // nos bonnes vieilles méthodes default Stream<E> stream() { return ... ; } }
  • 109. Interfaces Java 8 Une interface devient-elle une classe abstraite ?
  • 110. Interfaces Java 8 Une interface devient-elle une classe abstraite ? Non ! -une classe abstraite peut avoir des champs et possède un constructeur -un appel de méthode d’une classe abstraite (ou pas) est résolu à l’exécution -une implémentation par défaut est juste du code, lié à la compilation
  • 111. Méthodes par défaut Cela amène-t-il l’héritage multiple en Java ?
  • 112. Méthodes par défaut Cela amène-t-il l’héritage multiple en Java ? Oui, mais on l’a déjà
  • 113. Méthodes par défaut Cela amène-t-il l’héritage multiple en Java ? Oui, mais on l’a déjà public class String implements Serializable, Comparable<String>, CharSequence { // ... }
  • 114. Méthodes par défaut Ce que l’on a en Java est l’héritage multiple de type
  • 115. Méthodes par défaut Ce que l’on a en Java est l’héritage multiple de type Java 8 amène l’héritage multiple d’implémentation
  • 116. Méthodes par défaut Ce que l’on a en Java est l’héritage multiple de type Java 8 amène l’héritage multiple d’implémentation Ce que l’on a pas, c’est l’héritage multiple d’état
  • 117. Méthodes par défaut Ce que l’on a en Java est l’héritage multiple de type Java 8 amène l’héritage multiple d’implémentation Ce que l’on a pas, c’est l’héritage multiple d’état … et d’ailleurs, on n’en veut pas !
  • 118. Méthodes par défaut Peut-on avoir des conflits ?
  • 119. Méthodes par défaut Peut-on avoir des conflits ? Hélas oui…
  • 120. Méthodes par défaut Peut-on avoir des conflits ? Hélas oui… Il nous faut donc des règles pour les gérer
  • 121. Méthodes par défaut public class C implements A, B { // ... }
  • 122. Méthodes par défaut Exemple #1 public class C implements A, B { // ... } public interface A { default String a() { ... } } public interface B { default String a() { ... } }
  • 123. Méthodes par défaut Exemple #1 Erreur de compilation : class C inherits unrelated defaults for a() from types A and B public class C implements A, B { // ... } public interface A { default String a() { ... } } public interface B { default String a() { ... } }
  • 124. Méthodes par défaut Exemple #2 La classe gagne ! public class C implements A, B { public String a() { ... } } public interface A { default String a() { ... } } public interface B { default String a() { ... } }
  • 125. Méthodes par défaut Exemple #3 Le plus spécifique gagne ! public interface A extends B { default String a() { ... } } public interface B { default String a() { ... } } public class C implements A, B { // ... }
  • 126. Méthodes par défaut Retour sur l’exemple #1 On peut aussi faire un appel explicite public interface A { default String a() { ... } } public interface B { default String a() { ... } } public class C implements A, B { public String a() { return B.super.a() ; } }
  • 127. 2 règles simples Pour gérer les conflits de l’héritage multiple d’implémentation
  • 128. 2 règles simples Pour gérer les conflits de l’héritage multiple d’implémentation 1)La classe gagne
  • 129. 2 règles simples Pour gérer les conflits de l’héritage multiple d’implémentation 1)La classe gagne 2)Les implémentations les plus spécifiques gagnent
  • 130. Un exemple On a tous écrit une implémentation d’Iterator : public class MyIterator implements Iterator<E> { // du code métier super important public void remove() { throw new UnsupportedOperationException("Naaaaaaan !") ; } ; }
  • 131. Un exemple Grâce à Java 8 : Plus besoin d’écrire ce code ! public interface Iterator<E> { default void remove() { throw new UnsupportedOperationException("remove") ; } ; }
  • 132. Interfaces en Java 8 Donc on change le concept d’interfaces en Java 8 public class HelloWorld { // souvenir souvenir public static void main(String[] args) { System.out.println("Hello world!") ; } ; }
  • 133. Interfaces en Java 8 Donc on change le concept d’interfaces en Java 8 Vraiment… public interface HelloWorld { // souvenir souvenir public static void main(String[] args) { System.out.println("Hello world!") ; } ; }
  • 134. Interfaces en Java 8 1)Méthodes par défaut, héritage multiple d’implémentation règles pour gérer les conflits, qui s’appliquent à la compilation 2)Des méthodes statiques dans les interfaces Tout ceci va permettre de nouvelles manières d’écrire les APIs
  • 135. On en sommes-nous ? 1)On a une nouvelle syntaxe : les lambdas 2)On a un pattern à implémenter 3)On a des nouvelles interfaces qui permettent de conserver la compatibilité ascendante
  • 137. Qu’est-ce qu’un Stream ? D’un point de vue technique : une interface paramétrée « un stream de String »
  • 138. Qu’est-ce qu’un Stream ? D’un point de vue technique : une interface paramétrée D’autres interfaces pour les types primitifs : « un stream de String » IntStream, LongStream, DoubleStream
  • 139. Une nouvelle notion 1)Un stream ne porte pas de donnée Il s’agit juste d’un objet sur lequel on peut déclarer des opérations
  • 140. Une nouvelle notion 1)Un stream ne porte pas de donnée 2)Un stream ne peut pas modifier sa source Conséquence : il peut mener ses traitements en parallèle
  • 141. Une nouvelle notion 1)Un stream ne porte pas de donnée 2)Un stream ne peut pas modifier sa source 3)Une source peut être infinie, ou non bornée On a donc besoin de garantir que les calculs seront menés en temps fini
  • 142. Une nouvelle notion 1)Un stream ne porte pas de donnée 2)Un stream ne peut pas modifier sa source 3)Une source peut être infinie, ou non bornée 4)Un Stream traite ses données de façon lazy On peut optimiser les opérations entre elles On a besoin d’un mécanisme pour déclencher les traitements
  • 143. Comment construire un Stream ? De nombreuses façons de faire… 1)À partir d’une collection : Collection<String> collection = ... ; Stream<String> stream = collection.stream() ;
  • 144. Comment construire un Stream ? De nombreuses façons de faire… 1)À partir d’une collection : 2)À partir d’un tableau : Stream<String> stream2 = Arrays.stream(new String [] {"one", "two", "three"}) ;
  • 145. Comment construire un Stream ? De nombreuses façons de faire… 1)À partir d’une collection : 2)À partir d’un tableau : 3)À partir des méthodes factory de Stream Stream<String> stream1 = Stream.of("one", "two", "three") ;
  • 146. Comment construire un Stream ? Encore quelques patterns : Stream.empty() ; // Stream vide Stream.of(T t) ; // un seul élément Stream.generate(Supplier<T> s) ; Stream.iterate(T seed, UnaryOperator<T> f) ;
  • 147. Comment construire un Stream ? Encore d’autres façons : string.chars() ; // retourne un IntStream lineNumberReader.lines() ; // retourne un Stream<String> random.ints() ; // retourne un IntStream
  • 148. Deux types d’opérations On peut donc déclarer des opérations sur un Stream Deux types d’opérations : 1)Les opérations intermédiaires Exemple : map, filter
  • 149. Deux types d’opérations On peut donc déclarer des opérations sur un Stream Deux types d’opérations : 1)Les opérations intermédiaires Exemple : map, filter 2)Les opérations terminales, qui déclenchent le traitement Exemple : reduce
  • 150. Un premier exemple Retour sur notre map / filter / reduce // map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ; Construction d’un Stream sur une List
  • 151. Un premier exemple Retour sur notre map / filter / reduce // map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ; Déclarations
  • 152. Un premier exemple Retour sur notre map / filter / reduce // map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ; On lance le calcul
  • 153. Un premier exemple Retour sur notre map / filter / reduce // map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ; Valeur par défaut, dans le cas d’un stream vide
  • 154. Un Stream possède un état Les implémentations de Stream possèdent un état : -SIZED = le cardinal du Stream est connu -ORDERED = l’ordre du Stream est important (List) -DISTINCT = pas de doublon dans le Stream (Set) -SORTED = les Stream est trié (SortedSet)
  • 155. Un Stream possède un état Certaines opérations changent cet état -le filtrage annule SIZED -le mapping annule DISTINCT et SORTED
  • 156. Un Stream possède un état Et cela permet d’optimiser ! -un HashSet ne peut pas avoir de doublons…
  • 157. Un Stream possède un état Et cela permet d’optimiser ! -un HashSet ne peut pas avoir de doublons… -donc distinct() ne fait rien (NOP) pour un stream construit sur un HashSet
  • 158. Un Stream possède un état Et cela permet d’optimiser ! -un HashSet ne peut pas avoir de doublons… -donc distinct() ne fait rien (NOP) pour un stream construit sur un HashSet -un TreeSet est trié, donc…
  • 159. Un Stream possède un état Et cela permet d’optimiser ! -un HashSet ne peut pas avoir de doublons… -donc distinct() ne fait rien (NOP) pour un stream construit sur un HashSet -un TreeSet est trié, donc… -sorted() ne fait rien pour un stream construit sur un TreeSet
  • 160. Opérations stateless / statefull Opérations Stateless / statefull Certaines opérations sont stateless : Cela signifie que l’on n’a pas besoin de plus d’information que ce qui est contenu dans p persons.stream().map(p -> p.getAge()) ;
  • 161. Opérations stateless / statefull Opérations Stateless / statefull Certaines opérations sont stateless : Pas le cas de toutes les opérations persons.stream().map(p -> p.getAge()) ; stream.limit(10_000_000) ; // sélection des premiers 10M éléments
  • 162. Exemple Trions un tableau de String Random rand = new Random() ; String [] strings = new String[10_000_000] ; for (int i = 0 ; i < strings.length ; i++) { strings[i] = Long.toHexString(rand.nextLong()) ; }
  • 163. Exemple Trions un tableau de String Soooo Java 7… Random rand = new Random() ; String [] strings = new String[10_000_000] ; for (int i = 0 ; i < strings.length ; i++) { strings[i] = Long.toHexString(rand.nextLong()) ; }
  • 164. Exemple Trions un tableau de String Meilleur ? Random rand = new Random() ; Stream<String> stream = Stream.generate( () -> Long.toHexString(rand.nextLong()) ) ;
  • 165. Exemple Trions un tableau de String Meilleur ! // Random rand = new Random() ; Stream<String> stream = Stream.generate( () -> Long.toHexString(ThreadLocalRandom.current().nextLong()) ) ;
  • 166. Exemple Trions un tableau de String // other way Stream<String> stream = ThreadLocalRandom .current() .longs() // returns a LongStream .mapToObj(l -> Long.toHexString(l)) ;
  • 167. Exemple Trions un tableau de String // other way Stream<String> stream = ThreadLocalRandom .current() .longs() .mapToObj(Long::toHexString) ;
  • 168. Exemple Trions un tableau de String // other way Stream<String> stream = ThreadLocalRandom .current() .longs() .mapToObj(Long::toHexString) .limit(10_000_000) .sorted() ; T = 4 ms
  • 169. Exemple Trions un tableau de String // other way Stream<String> stream = ThreadLocalRandom .current() .longs() .mapToObj(Long::toHexString) .limit(10_000_000) .sorted() ; Object [] sorted = stream.toArray() ;
  • 170. Exemple Trions un tableau de String // other way Stream<String> stream = ThreadLocalRandom .current() .longs() .mapToObj(Long::toHexString) .limit(10_000_000) .sorted() ; Object [] sorted = stream.toArray() ; T = 14 s
  • 171. Exemple Trions un tableau de String // other way Stream<String> stream = ThreadLocalRandom .current() .longs() .mapToObj(Long::toHexString) .limit(10_000_000) .sorted() ; Object [] sorted = stream.toArray() ; T = 14 s Opérations intermédiaires !
  • 172. Au final 1)Il y a des opérations intermédiaires, et des opérations terminales 2)Seule une opération terminale déclenche les traitements
  • 173. Au final 1)Il y a des opérations intermédiaires, et des opérations terminales 2)Seule une opération terminale déclenche les traitements 3)Une seule opération terminale est autorisée 4)Un Stream ne peut traité qu’une seule fois Si besoin, un autre Stream doit être construit
  • 175. Optimisation La première optimisation (après l’exécution lazy) est le parallélisme Fork / join permet la programmation parallèle depuis le JDK 7 Écrire du code parallèle reste complexe, et ne mène pas toujours à de meilleures performances
  • 176. Optimisation La première optimisation (après l’exécution lazy) est le parallélisme Fork / join permet la programmation parallèle depuis le JDK 7 Écrire du code parallèle reste complexe, et ne mène pas toujours à de meilleures performances Utiliser l’API Stream est plus simple et plus sûr
  • 177. Construction d’un Stream parallèle Deux patterns 1)Appeler parallelStream() au lieu de stream() 2)Appeler parallel() sur un stream existant Stream<String> s = strings.parallelStream() ; Stream<String> s = strings.stream().parallel() ;
  • 178. Paralléliser est-il aussi simple ? En fait oui !
  • 179. Paralléliser est-il aussi simple ? En fait oui ! … et non…
  • 180. Paralléliser est-il aussi simple ? Exemple 1 : « retourne les premiers 10M éléments » persons.stream().limit(10_000_000) ;
  • 181. Paralléliser est-il aussi simple ? Exemple 1 : performances Code 1 List<Long> list = new ArrayList<>(10_000_100) ; for (int i = 0 ; i < 10_000_000 ; i++) { list1.add(ThreadLocalRandom.current().nextLong()) ; }
  • 182. Paralléliser est-il aussi simple ? Exemple 1 : performances Code 2 Stream<Long> stream = Stream.generate(() -> ThreadLocalRandom.current().nextLong()) ; List<Long> list1 = stream.limit(10_000_000).collect(Collectors.toList()) ;
  • 183. Paralléliser est-il aussi simple ? Exemple 1 : performances Code 3 Stream<Long> stream = ThreadLocalRandom.current().longs(10_000_000).mapToObj(Long::new) ; List<Long> list = stream.collect(Collectors.toList()) ;
  • 184. Paralléliser est-il aussi simple ? Exemple 1 : performances Série Parallèle Code 1 (for) 270 ms Code 2 (limit) 310 ms Code 3 (longs) 250 ms
  • 185. Paralléliser est-il aussi simple ? Exemple 1 : performances Série Parallèle Code 1 (for) 270 ms Code 2 (limit) 310 ms 500 ms Code 3 (longs) 250 ms 320 ms
  • 186. Parallélisme Le parallélisme implique des calculs supplémentaires la plupart du temps Des opérations mal configurées vont entraîner des calculs inutiles, qui vont affaiblir les performances globales Exemple : un stream ORDERED est plus complexe à traiter
  • 188. La réduction simple La somme des âges // map / filter / reduce int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;
  • 189. La réduction simple Ca serait bien de pouvoir écrire : Mais sum() n’est pas définie sur Stream<T> Que voudrait dire « additionner des personnes » ? // map / filter / reduce int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .sum() ;
  • 190. La réduction simple Ca serait bien de pouvoir écrire : Mais sum() n’est pas définie sur Stream<T> Mais il y a une méthode sum() sur IntStream ! // map / filter / reduce int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .sum() ;
  • 191. La réduction simple 2ème version : Résultat pour une liste vide : 0 // map / filter / reduce int sum = persons.stream() .map(Person::getAge) .filter(a -> a > 20) .mapToInt(Integer::intValue) .sum() ;
  • 192. La réduction simple 2ème version (encore meilleure) : Résultat pour une liste vide : 0 // map / filter / reduce int sum = persons.stream() .mapToInt(Person::getAge) .filter(a -> a > 20) // .mapToInt(Integer::intValue) .sum() ;
  • 193. La réduction simple Qu’en est-il de min() et de max() ? Quelle valeur par défaut pour max() ? // map / filter / reduce ....... = persons.stream() .mapToInt(Person::getAge) .filter(a -> a > 20) .max() ;
  • 194. Problème des valeurs par défaut La notion de « valeur par défaut » est plus complexe qu’il y paraît…
  • 195. Problème des valeurs par défaut La notion de « valeur par défaut » est plus complexe qu’il y paraît… 1)La « valeur par défaut » est la réduction de l’ensemble vide
  • 196. Problème des valeurs par défaut La notion de « valeur par défaut » est plus complexe qu’il y paraît… 1)La « valeur par défaut » est la réduction de l’ensemble vide 2)Mais aussi l’élément neutre de la réduction
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205. Problème des valeurs par défaut Problème : max() and min() n’ont pas d’élément neutre ie : un élément e pour lequel max(e, a) = a
  • 206. Problème des valeurs par défaut Problème : max() and min() n’ont pas d’élément neutre ie : un élément e pour lequel max(e, a) = a Ca ne peut pas être 0 : max(-1, 0) = 0 −∞ n’est pas un entier
  • 207. Problème des valeurs par défaut Donc quelle est la valeur par défaut de max() et min() ?
  • 208. Problème des valeurs par défaut Donc quelle est la valeur par défaut de max() et min() ? Réponse : il n’y a pas de valeur par défaut pour max() et pour min()
  • 209. Problème des valeurs par défaut Donc quel type choisir pour la méthode max() ? // map / filter / reduce pattern on collections ....... = persons.stream() .mapToInt(Person::getAge) .filter(a -> a > 20) .max() ;
  • 210. Problème des valeurs par défaut Donc quel type choisir pour la méthode max() ? Si c’est int, la valeur par défaut sera 0… // map / filter / reduce pattern on collections ....... = persons.stream() .mapToInt(Person::getAge) .filter(a -> a > 20) .max() ;
  • 211. Optionals Sans valeur par défaut, il faut trouver autre chose… // map / filter / reduce pattern on collections OptionalInt optionalMax = persons.stream() .mapToInt(Person::getAge) .filter(a -> a > 20) .max() ; « il peut ne pas y avoir de résultat »
  • 212. Optionals Que peut-on faire avec OptionalInt ? 1er pattern : tester s’il contient une valeur OptionalInt optionalMax = ... ; int max ; if (optionalMax.isPresent()) { max = optionalMax.get() ; } else { max = ... ; // décider d’une « valeur par défaut » }
  • 213. Optionals Que peut-on faire avec OptionalInt ? 2ème pattern : lire la valeur ou jeter une exception OptionalInt optionalMax = ... ; // throws NoSuchElementException if no held value int max = optionalMax.getAsInt() ;
  • 214. Optionals Que peut-on faire avec OptionalInt ? 3ème pattern : lire la valeur / retourner une valeur par défaut OptionalInt optionalMax = ... ; // get 0 if no held value int max = optionalMax.orElse(0) ;
  • 215. Optionals Que peut-on faire avec OptionalInt ? 4ème pattern : lire la valeur ou jeter une exception OptionalInt optionalMax = ... ; // exceptionSupplier will supply an exception, if no held value int max = optionalMax.orElseThrow(exceptionSupplier) ;
  • 216. Available Optionals Optional<T> OptionalInt, OptionalLong, OptionalDouble
  • 217. Réductions disponibles Sur Stream<T> : -reduce() -count(), min(), max() -anyMatch(), allMatch(), noneMatch() -findFirst(), findAny() -toArray() -forEach(), forEachOrdered()
  • 218. Réductions disponibles Sur IntStream, LongStream, DoubleStream : -average() -sum() -summaryStatistics()
  • 220. Mutable reductions : exemple 1 Utilisation d’une classe helper : Collectors ArrayList<String> strings = stream .map(Object::toString) .collect(Collectors.toList()) ;
  • 221. Mutable reductions : exemple 2 Concaténation de String avec un helper String names = persons .stream() .map(Person::getName) .collect(Collectors.joining()) ;
  • 222. Mutable reductions Une réduction mutable dépend : -d’un container : Collection or StringBuilder -d’un moyen d’ajouter un élément au container -d’un moyen de fusionner deux containers (utilisé dans les opérations parallèles)
  • 224. La classe Collectors Une boite à outils (37 méthodes) pour la plupart des types de réduction -counting, minBy, maxBy -summing, averaging, summarizing -joining -toList, toSet, toMap Et - mapping, groupingBy, partionningBy
  • 225. La classe Collectors Average, Sum, Count persons .stream() .collect(Collectors.averagingDouble(Person::getAge)) ; persons .stream() .collect(Collectors.counting()) ;
  • 226. La classe Collectors Concaténation des noms dans une String String names = persons .stream() .map(Person::getName) .collect(Collectors.joining(", ")) ;
  • 227. La classe Collectors Accumulation dans un Set Set<Person> setOfPersons = persons .stream() .collect( Collectors.toSet()) ;
  • 228. La classe Collectors Accumulation dans une collection passée en paramètre TreeSet<Person> treeSetOfPersons = persons .stream() .collect( Collectors.toCollection(TreeSet::new)) ;
  • 229. La classe Collectors Calculer un max avec un comparateur Bonus : une API Comparator Optional<Person> optionalPerson = persons .stream() .collect( Collectors.maxBy( Comparator.comparing(Person::getAge)) ;
  • 230. Construction de comparateurs Nouvelle API pour construire des comparateurs Comparator<Person> comp = Comparator.comparing(Person::getLastName) .thenComparing(Person::getFirstName) .thenComparing(Person::getAge) ;
  • 231. Classe Collectors : mapping La méthode mapping() prend 2 paramètres -une fonction, qui mappe les éléments du Stream -un collecteur, appelé « downstream », appliqué aux valeurs mappées
  • 232. Classe Collectors : mapping Accumuler les noms des personnes dans un Set Set<String> set = persons .stream() .collect( Collectors.mapping( Person::getLastName, Collectors.toSet())) ;
  • 233. Classe Collectors : mapping Mapper le stream, accumulation dans une collection TreeSet<String> set = persons .stream() .collect( Collectors.mapping( Person::getLastName, Collectors.toCollection(TreeSet::new)) ) ;
  • 234. Classe Collectors : groupingBy « Grouping by » construit des tables de hachage -méthode de construction des clés -par défaut les éléments sont rangés dans une liste -on peut spécifier un downstream (collector)
  • 235. Classe Collectors : groupingBy Des personnes par âge Map<Integer, List<Person>> map = persons .stream() .collect( Collectors.groupingBy( Person::getAge)) ;
  • 236. Classe Collectors : groupingBy … rangées dans des Set Map<Integer, Set<Person>> map = persons .stream() .collect( Collectors.groupingBy( Person::getAge, Collectors.toSet() // le downstream ) ;
  • 237. Classe Collectors : groupingBy … on ne garde que les noms Map<Integer, Set<String>> map = persons .stream() .collect( Collectors.groupingBy( Person::getAge, Collectors.mapping( // Person::getLastName, // the downstream Collectors.toSet() // ) ) ;
  • 238. Classe Collectors : groupingBy … les noms rangés dans des TreeSet Map<Integer, TreeSet<String>> map = persons .stream() .collect( Collectors.groupingBy( Person::getAge, Collectors.mapping( Person::getLastName, Collectors.toCollection(TreeSet::new) ) ) ;
  • 239. Classe Collectors : groupingBy … etc… etc… etc… TreeMap<Integer, TreeSet<String>> map = persons .stream() .collect( Collectors.groupingBy( Person::getAge, TreeMap::new, Collectors.mapping( Person::getLastName, Collectors.toCollection(TreeSet::new) ) ) ;
  • 240. Classe Collectors : groupingBy Exemple : création d’un histogramme des âges Donne le nombre de personnes par âge Map<Integer, Long> map = persons .stream() .collect( Collectors.groupingBy( Person::getAge, Collectors.counting() ) ) ;
  • 241. Classe Collectors : partionningBy Crée une Map<Boolean, …> à partir d’un prédicat -la table a deux clés : TRUE et FALSE -et on peut y ajouter un downstream
  • 242. Classe Collectors : partionningBy Crée une Map<Boolean, …> avec un prédicat map.get(TRUE) retourne la liste des personnes de plus de 20 ans Map<Boolean, List<Person>> map = persons .stream() .collect( Collectors.partitioningBy(p -> p.getAge() > 20) ) ;
  • 243. Classe Collectors : partionningBy On peut définir d’autres traitements Map<Boolean, TreeSet<String>> map = persons .stream() .collect( Collectors.partitioningBy( p -> p.getAge() > 20, Collectors.mapping( Person::getLastName, Collectors.toCollection(TreeSet::new)) ) ) ) ;
  • 244. Classe Collectors : collectingAndThen Collecte les données avec un downstream Applique enfin une fonction appelée « finisher » Indispensable pour retourner des collections immutables
  • 245. Classe Collectors : collectingAndThen Dans ce cas « Map::entrySet » est un finisher Set<Map.Entry<Integer, List<Person>>> set = persons .stream() .collect( Collectors.collectingAndThen( Collectors.groupingBy( Person::getAge), // downstream, construit une map Map::entrySet // finisher, appliqué à la map ) ;
  • 247. 1er exemple Optional<Entry<Integer, Long>> opt = movies.stream().parallel() .collect( Collectors.collectingAndThen( Collectors.groupingBy( movie -> movie.releaseYear(), Collectors.counting() ), Map::entrySet ) ) .stream() .max(Map.Entry.comparingByValue()) ;
  • 248. 1er exemple Optional<Entry<Integer, Long>> opt = movies.stream().parallel() .collect( Collectors.collectingAndThen( Collectors.groupingBy( movie -> movie.releaseYear(), Collectors.counting() ), Map::entrySet ) ) .stream() .max(Map.Entry.comparingByValue()) ; Un stream de movies
  • 249. 1er exemple Optional<Entry<Integer, Long>> opt = movies.stream().parallel() .collect( Collectors.collectingAndThen( Collectors.groupingBy( movie -> movie.releaseYear(), Collectors.counting() ), Map::entrySet ) ) .stream() .max(Map.Entry.comparingByValue()) ; Construction d’une map année / # de films
  • 250. 1er exemple Optional<Entry<Integer, Long>> opt = movies.stream().parallel() .collect( Collectors.collectingAndThen( Collectors.groupingBy( movie -> movie.releaseYear(), Collectors.counting() ), Map::entrySet ) ) .stream() .max(Map.Entry.comparingByValue()) ; Construction de l’EntrySet
  • 251. 1er exemple Optional<Entry<Integer, Long>> opt = movies.stream().parallel() .collect( Collectors.collectingAndThen( Collectors.groupingBy( movie -> movie.releaseYear(), Collectors.counting() ), Map::entrySet ) ) .stream() .max(Map.Entry.comparingByValue()) ; Et déterminer la plus grande valeur
  • 252. 1er exemple Optional<Entry<Integer, Long>> opt = movies.stream().parallel() .collect( Collectors.collectingAndThen( Collectors.groupingBy( movie -> movie.releaseYear(), Collectors.counting() ), Map::entrySet ) ) .stream() .max(Map.Entry.comparingByValue()) ; Retourne l’année qui a vu le plus grand nombre de films
  • 254. Conclusion Pourquoi les lambdas ont-ils été introduits dans Java 8 ?
  • 255. Conclusion Pourquoi les lambdas ont-ils été introduits dans Java 8 ? Réponse : parce que c’est à la mode !
  • 256.
  • 257. Conclusion Pourquoi les lambdas ont-ils été introduits dans Java 8 ? Réponse : parce que c’est à la mode !
  • 258. Conclusion Pourquoi les lambdas ont-ils été introduits dans Java 8 ? Réponse : parce que c’est à la mode ! Parce que le code écrit est plus compact !
  • 259. Plus c’est court, plus c’est bon ! Un exemple de code compact #include "stdio.h" main() { int b=0,c=0,q=60,_=q;for(float i=-20,o,O=0,l=0,j,p;j=O*O,p=l*l, (!_--|(j+p>4)?fputc(b?q+(_/3):10,(i+=!b,p=j=O=l=0,c++,stdout)), _=q:l=2*O*l+i/20,O=j-p+o),b=c%q,c<2400;o=-2+b*.05) ; } http://www.codeproject.com/Articles/2228/Obfuscating-your-Mandelbrot-code
  • 260. Un exemple de code compact #include "stdio.h" main() { int b=0,c=0,q=60,_=q;for(float i=-20,o,O=0,l=0,j,p;j=O*O,p=l*l, (!_--|(j+p>4)?fputc(b?q+(_/3):10,(i+=!b,p=j=O=l=0,c++,stdout)), _=q:l=2*O*l+i/20,O=j-p+o),b=c%q,c<2400;o=-2+b*.05) ; } http://www.codeproject.com/Articles/2228/Obfuscating-your-Mandelbrot-code ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++ ++ +++++++++++ +++++++++++++++++++++++++++++++++++ +++++++ ++++++++++++++++++++++++++++++++++++ +++++++ +++++++++++++++++++++++++++++++++++ ++++++++ ++++++++++++++++++++++++++++++++++ +++++++ +++++++++++++++++++++++++++++++++ +++++ +++++++++++++++++++++++++++++++++ ++++++ +++++++++++++++++++++++ + +++++ ++++++ +++++++++++++++++++++++ ++ ++++++ ++++++++++++++++++++++ + ++++++ ++++++++++++++++++++++ + ++++++ ++++++++++++++++++++ + + +++++++ ++++++ ++++++++ ++++++++++++++++++++ + + +++++++ ++++++++++++++++++++++ + ++++++ ++++++++++++++++++++++ + ++++++ +++++++++++++++++++++++ ++ ++++++ +++++++++++++++++++++++ + +++++ ++++++ +++++++++++++++++++++++++++++++++ ++++++ +++++++++++++++++++++++++++++++++ +++++ ++++++++++++++++++++++++++++++++++ +++++++ +++++++++++++++++++++++++++++++++++ ++++++++ ++++++++++++++++++++++++++++++++++++ +++++++ +++++++++++++++++++++++++++++++++++ +++++++ ++++++++++++++++++++++++++++++++++++ ++ +++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Plus c’est court, plus c’est bon !
  • 261. Conclusion Pourquoi les lambdas ont-ils été introduits dans Java 8 ? Réponse : parce que c’est à la mode ! Parce que le code écrit est plus compact !
  • 262. Conclusion Pourquoi les lambdas ont-ils été introduits dans Java 8 ? Parce que les lambdas autorisent des nouveaux patterns qui permettent de paralléliser les traitements simplement et de façon sûre -dont les applications ont besoin -dont concepteurs d’API ont besoin
  • 263. Conclusion Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe
  • 264. Conclusion Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe Migrer vers Java 8 va nécessiter du travail pour nous les développeurs -auto-formation -changement de nos habitudes de programmer
  • 265. Conclusion Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe Migrer vers Java 8 va nécessiter du travail pour nous les développeurs -auto-formation -changement de nos habitudes de programmer -convaincre nos boss…
  • 266. Conclusion Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe Téléchargeons la version développeur sur openjdk.net Date de sortie : 18 mars 2014
  • 267. Conclusion Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe « Java is a blue collar language. It’s not PhD thesis material but a language for a job » – James Gosling, 1997
  • 268. Conclusion Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe « Language features are not a goal unto themselves; language features are enablers, encouraging or discouraging certain styles and idioms » – Brian Goetz, 2013
  • 269. Conclusion Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe La bonne nouvelle : Java est toujours Java !