SlideShare ist ein Scribd-Unternehmen logo
1 von 330
Downloaden Sie, um offline zu lesen
JDK 8 & Lambdas

Lambdas, Streams, Collectors
Pourquoi ont-ils été introduits ?
Pourquoi ont-ils été introduits ?
Pourquoi sont-ils si importants ?
Pourquoi ont-ils été introduits ?
Pourquoi sont-ils si importants ?
Comment vont-ils changer nos habitudes de
programmation ?
Introduisons les lambdas
Introduisons les lambdas
sur un exemple simple
Un exemple très simple
public class Person {

Un bon vieux bean

private String name ;
private int age ;
// constructors
// getters / setters

}

List<Person> list = new ArrayList<>() ;

… et une bonne vieille liste
Calculons la moyenne des âges des personnes
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() ;
}
Plus dur : pour les personnes de plus de 20 ans
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
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 ;
}

« programmation impérative »
… pas une obligation !
select avg(age)
from Person
where age > 20

Ici on décrit le résultat
… pas une obligation !
select avg(age)
from Person
where age > 20

© SQL 1974

Ici on décrit le résultat
Dans ce cas la base de données mène le calcul
comme elle l’entend
map
Person

age

1ère étape : mapping

age > 20

sum
map
Person

age

age > 20

1ère étape : mapping
Mapping :
- prend une liste d’un type donné
- retourne une liste d’un autre type
- possède le même nombre d’éléments

sum
map
Person

filter
age

2ème étape : filtrage

age > 20

sum
map
Person

filter
age

age > 20

2ème étape : filtrage
Filtrage :
- prend une liste d’un type donné
- retourne une liste du même type
- mais avec moins d’éléments

sum
map
Person

filter
age

3ème étape : réduction

reduce
age > 20

sum
map
Person

filter
age

reduce
age > 20

sum

3ème étape : réduction
Reduction : agrégation des éléments d’une
liste dans un seul élément
Ex : moyenne, somme, min, max, etc…
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) ;
}
La façon JDK 7
… et on crée une classe anonyme
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
On peut faire la même chose pour le filtrage
public interface Predicate<T> {
public boolean filter(T t) ;
}
La façon JDK 7
On peut faire la même chose pour le filtrage
public interface Predicate<T> {
public boolean filter(T t) ;
}
AgePredicate predicate = new Predicate<Integer>() {

public boolean filter(Integer i) {
return i > 20 ;
}
}
La façon JDK 7
Et enfin pour la réduction
public interface Reducer<T> {
public T reduce(T t1, T t2) ;
}
La façon JDK 7
Et enfin pour la réduction
public interface Reducer<T> {
public T reduce(T t1, T t2) ;
}
Reducer<Integer> reduction = new Reducer<Integer>() {

public Integer reduce(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
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
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…
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 du JDK 8
La façon du JDK 8
Prenons l’exemple du Mapper
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() ;
}
}
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 p.getAge() ;
On prend
}
}
person
mapper = (Person 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() ;
}
}
et…
mapper = (Person 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() ;
}
}
… on retourne
mapper = (Person person) -> person.getAge() ;

son âge
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() ;
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() ;

Le compilateur reconnaît cette expression comme une
implémentation du mapper
Que se passe-t-il si …
… il y a plus d’une ligne de code ?
mapper = (Person person) -> {
System.out.println("Mapping " + person) ;
return person.getAge() ;
}

Accolades, un return explicite
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 ?
reducer = (int i1, int i2) -> {
return i1 + i2 ;
}

Ou :
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() ;
La façon du JDK 8
Comment le compilateur reconnaît-il l’implémentation du
mapper ?
mapper = (Person person) -> person.getAge() ;

1) Il ne faut qu’une méthode dans le mapper
La façon du JDK 8
Comment le compilateur reconnaît-il l’implémentation du
mapper ?
mapper = (Person person) -> person.getAge() ;

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
La façon du JDK 8
Comment le compilateur reconnaît-il l’implémentation du
mapper ?
mapper = (Person person) -> person.getAge() ;

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
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
D’autres lambdas
Et la plupart du temps, le compilateur reconnaît ceci :
mapper = person -> person.getAge() ; // mapper
filter = age -> age > 20 ; // filter
reducer = (i1, i2) -> i1 + i2 ; // reducer

Le type des paramètres peut être omis
Une remarque sur la réduction
Comment cela fonctionne-t-il réellement ?
Réduction
2 exemples :
Reducer r1 = (i1, i2) -> i1 + i2 ; // Ok

Reducer r2 = (i1, i2) -> i1*i1 + i2*i2 ; // Oooops

Attention :
le résultat est toujours reproductible en série
il ne l’est en général pas en parallèle
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 :
mapper = person -> person.getAge() ;

Mais on peut aussi écrire :
mapper = Person::getAge ; // méthode non statique
Il y a d’autres syntaxes
On peut écrire :
sum = (i1, i2) -> i1 + i2 ;
sum = Integer::sum ; // méthode statique, nouvelle !

Ou encore :
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 »
@FunctionalInterface
public interface Consumer<T> {
public void accept(T t) ;
}

- ne possède qu’une unique méthode
Modélisation
Un lambda = instance d’une « interface fonctionnelle »
@FunctionalInterface
public interface Consumer<T> {
public void accept(T t) ;
}

- ne possède qu’une unique méthode
- peut être annotée par @FunctionalInterface (optionnel)
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) ;
}
} ;

Donc :
Consumer<String> c = s -> System.out.println(s) ;
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) ;
}
} ;

Question : qu’est-ce que s ?

Donc :
Consumer<String> c = s -> System.out.println(s) ;
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) ;
}
} ;

Donc :

Réponse : le
compilateur infère qu’il
s’agit d’un String

Consumer<String> c = s -> System.out.println(s) ;
Mettre un lambda dans une variable
Question : peut-on écrire ce code ?
int i = ... ;
Consumer<String> c = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("i = " + i) ;
}
} ;
Mettre un lambda dans une variable
Question : peut-on écrire ce code ?
int i = ... ;
Consumer<String> c = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("i = " + i) ;
}
} ;

JDK 7 : i doit être final
Mettre un lambda dans une variable
Question : peut-on écrire ce code ?
int i = ... ;
Consumer<String> c = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("i = " + i) ;
}
} ;

JDK 8 : ce code compile
Mettre un lambda dans une variable
En revanche, ce code …
int i = ... ;
Consumer<String> c = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("i = " + i) ;
}
} ;
i = i + 1 ;

… ne compile pas
Mettre un lambda dans une variable
Raison : le compilateur infère que i est effectivement final
final int i = ... ;
Consumer<String> c = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("i = " + i) ;
}
} ;
i = i + 1 ; // on ne peut pas modifier i
Note au sujet de this
JDK 7 : this est l’instance anonyme
Consumer<String> c = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("this = " + this) ;
}
public String toString() {
return "je suis dans c" ;
}

} ;

Appeler accept() affiche donc « je suis dans c »
Note au sujet de this
JDK 8 : idem, accept() affiche « je suis dans c »
Consumer<String> c = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("this = " + this) ;
}
public String toString() {
return "je suis dans c" ;
}

} ;

Mais …
Note au sujet de this
Un consommateur peut aussi s’écrire comme ça :
Consumer<String> c = s -> System.out.println(this) ;

Dans ce cas, this est l’instance englobante
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) ;
BiConsumer
Prend deux arguments au lieu d’un
Peuvent être chaînés
Versions types primitifs :
- ObjIntConsumer
- ObjLongConsumer
- ObjDoubleConsumer
ObjIntConsumer prend un objet et un int en arguments
Function
Une fonction prend un objet et retourne un autre objet
public interface Function<T, R> {

R apply(T t) ;
}

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
Predicate
Un Predicate prend un objet et retourne un booléen
public interface Predicate<T> {

boolean test(T t) ;
}

Il peut être inversé, et composé avec des AND ou OR
BiPredicate
Un BiPredicate prend deux objets et retourne un booléen
public interface BiPredicate<T, U> {

boolean test(T t, U u) ;
}

Version pour les types booléens
Retour sur
map / filter / reduce
La façon JDK 7
Comment implémenter le pattern map / filter / reduce
sur List<Person> ?
La façon JDK 7
Comment implémenter le pattern map / filter / reduce
sur List<Person> ?
La façon classique est d’itérer sur les éléments et
d’appliquer le pattern
La façon JDK 7
Comment implémenter le pattern map / filter / reduce
sur List<Person> ?
La façon classique est d’itérer sur les éléments et
d’appliquer le pattern
On peut pour cela créer une méthode helper
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 :
// 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 :
// 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) ;

L’idée est de pousser un lambda vers l’implémentation, et
de la laisser itérer en interne
Pattern complet
Le pattern va ressembler à ça :
// 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) ;

Pour : l’API peut être optimisée sans
que l’on ait à toucher au code, super !
Pattern complet
Le pattern va ressembler à ça :
// 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) ;

Pour : l’API peut être optimisée sans
que l’on ait à toucher au code, super !
Contre…
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
// 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) ;

2 duplications : ages & agesGT20
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) ;

2 duplications : ages & agesGT20
Que fait-on de ces listes ? On les envoie au GC !
Pattern complet
2) Supposons que les algorithmes de calcul du map / filter /
reduce soient déjà optimisés
// 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 les algorithmes de calcul du map / filter /
reduce soient déjà optimisés
// 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) ;

… mais on doit encore gagner du temps !
Pattern complet
2) Supposons que les algorithmes de calcul du map / filter /
reduce soient déjà optimisés
// 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) ;

Seule solution : paralléliser !
Pattern complet
2) Supposons que l’on veuille paralléliser…
// 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) ;

Il faut mieux que ages et agesGT20 soient des collections
concurrentes !
Pattern complet
3) Supposons que nous aillons un reducer : 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) ;

allMatch est vrai si tous les noms sont plus courts que 20
caractères
Voyons une implémentation possible de allMatch()
É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 ;
}
É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 !
É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 ;
}

Sauf que…
Pattern complet
Quand on applique la réduction allMatch()…
// pattern map / filter / reduce
List<Person> persons = ... ;
List<String> names =
Lists.map(persons, p -> p.getName()) ;
boolean allMatch =
Lists.allMatch(names, n.length() < 20) ;

… names a déjà été évaluée !
Pattern complet
Quand on applique la réduction allMatch()…
// pattern map / filter / reduce
List<Person> persons = ... ;
List<String> names =
Lists.map(persons, p -> p.getName()) ;
boolean allMatch =
Lists.allMatch(names, n.length() < 20) ;

… names a déjà été évaluée !
On a perdu une belle optimisation…
Pattern complet
Quand on applique la réduction allMatch()…
// pattern map / filter / reduce
List<Person> persons = ... ;
List<String> names =
Lists.map(persons, p -> p.getName()) ;
boolean allMatch =
Lists.allMatch(names, n.length() < 20) ;

… names a déjà été évaluée !
Il aurait fallu appliquer le mapping de façon lazy
Conclusion
Pour : 1
Contre : 3 (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) ;
Conclusion
Pour : 1
Contre : 3 (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) ;
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
Conclusion (again)
On a besoin d’un nouveau concept pour traiter les listes de
grande taille de façon efficace
Le framework Collection n’apporte pas de solution
satisfaisante
Conclusion (again)
On a besoin d’un nouveau concept pour traiter les listes de
grande taille de façon efficace
Le framework Collection n’apporte pas de solution
satisfaisante
On a besoin de quelque chose d’autre !
Quel pattern choisir ?
Introduction
Implémenter le map / filter / reduce sur Collection aurait
mené à ceci :
// map / filter / reduce pattern sur Collection
int sum = persons
.map(p -> p.getAge())
.filter(a -> a > 20)
.reduce(0, (a1, a2) -> a1 + a2) ;

Et même si cette approche n’est pas viable, c’est une
façon agréable d’écrire les choses
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
// 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 = on a les mains libres !
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() ;

}
Interfaces
Problème : ArrayList ne compile plus…
Une solution doit être trouvée !
Une solution qui ne nécessite pas de modifier ou de
recompiler toutes les implémentations existantes de
Collection !
Nouvelles interfaces
Interfaces Java 8
Problème : ArrayList ne compile plus…
Une solution doit être trouvée !
Une solution qui ne nécessite pas de modifier ou de
recompiler toutes les implémentations existantes de
Collection !
Problème : ajouter des méthodes à une interface sans
toucher aux implémentations…
Interfaces Java 8
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
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
Introduisons les default methods en Java
public interface Collection<E> {
// nos bonnes vieilles méthodes
default Stream<E> stream() {
return ... ;
}

}

Les méthodes par défaut permettent de faire évoluer de
vieilles interfaces
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 mutliple 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
public class C
implements A, B {
// ...
}

public interface A {
default String a() { ... }
}

public interface B {
default String a() { ... }
}
Méthodes par défaut
public class C
implements A, B {
public String a() { ... }
}

Exemple #0
public interface A {
default String a() { ... }
}

public interface B {
default String a() { ... }
}

La classe gagne !
L’implémentation efface la méthode par défaut
Méthodes par défaut
public class C
implements A, B {
// ...
}

Exemple #1
public interface A {
default String a() { ... }
}

public interface B {
default String a() { ... }
}
Méthodes par défaut
public class C
implements A, B {
// ...
}

Exemple #1
public interface A {
default String a() { ... }
}

public interface B {
default String a() { ... }
}

Erreur de compilation :
class C inherits unrelated defaults for a() from types A and B
Méthodes par défaut
public class C
implements A, B {
// ...
}

Exemple #2
public interface A extends B {
default String a() { ... }
}

public interface B {
default String a() { ... }
}

A est plus spécifique que B : A.a() a la priorité
Méthodes par défaut
public class D extends C
implements B {
// ...
}

public class C
implements A {
// ...
}

Exemple #2
public interface A extends B {
default String a() { ... }
}

public interface B {
default String a() { ... }
}
Méthodes par défaut
public class D extends C
implements B {
// ...
}

public class C
implements A {
// ...
}

Exemple #2
public interface A extends B {
default String a() { ... }
}

public interface B {
default String a() { ... }
}

A est toujours plus spécifique que B : A.a() gagne
Méthodes par défaut
public class C
implements A, B {
public String a() { return B.super.a() ; }
}

Retour sur l’exemple #1
public interface A {
default String a() { ... }
}

public interface B {
default String a() { ... }
}

On peut aussi faire un appel explicite
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 :
public interface Iterator<E> {
default void remove() {
throw new UnsupportedOperationException("remove") ;
} ;
}

Plus besoin d’écrire ce code !
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

« un stream de String »
D’autres interfaces pour les types primitifs :

IntStream, LongStream, DoubleStream
Une nouvelle notion
Cela ressemble à une collection, mais…
- Un Stream est construit sur une « source »
- Pas de donnée à la construction
- Pas de limite sur ce qu’une source peut produire
Une nouvelle notion
Un Stream peut être construit sur :
- Une collection ou un tableau
- Un itérateur
- Un source I/O
Certaines de ces sources sont « infinies »
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)
2)
3)
4)

Un stream ne porte pas de donnée
Un stream ne peut pas modifier sa source
Une source peut être infinie, ou non bornée
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
Un Stream est-il une Collection ?
La réponse est non
Un Stream est-il une Collection ?
La réponse est non
Une collection permet d’itérer sur ses éléments
Un Stream est-il une Collection ?
La réponse est non
Une collection permet d’itérer sur ses éléments
Pas un Stream
Un Stream est-il une Collection ?
La réponse est non
Une collection ne permet pas d’appliquer un lambda sur
ses éléments
Un Stream est-il une Collection ?
La réponse est non
Une collection ne permet pas d’appliquer un lambda sur
ses éléments
Un Stream le peut
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
Un premier exemple
Retour sur notre map / filter / reduce
Construction d’un
collections
Stream sur une List

// map / filter / reduce pattern on
int sum = persons.stream()
.map(p -> p.getAge())
.filter(a -> a > 20)
.reduce(0, (a1, a2) -> a1 + a2) ;
Un premier exemple
Retour sur notre map / filter / reduce
Déclarations
// map / filter / reduce pattern on collections
int sum = persons.stream()
.map(p -> p.getAge())
.filter(a -> a > 20)
.reduce(0, (a1, a2) -> a1 + a2) ;
Un premier exemple
Retour sur notre map / filter / reduce
On lance le
collections
calcul

// map / filter / reduce pattern on
int sum = persons.stream()
.map(p -> p.getAge())
.filter(a -> a > 20)
.reduce(0, (a1, a2) -> a1 + a2) ;
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
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 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…
- sort() ne fait rien pour un stream construit sur un
TreeSet
Un

ème
2

exemple

Trions une liste de chaîne de caractères
List<String> strings = new ArrayList<>() ;
// on remplit la liste
// et plus loin dans le code on a ça :
List<String> result = strings.stream()
.sorted()
.collect(Collector.toList()) ;
Un

ème
2

exemple

Trions une liste de chaîne de caractères
// un jour un petit malin change l’implémentation
SortedSet<String> strings = new TreeSet<>() ;
// on remplit la liste
// et plus loin dans le code on a ça :
List<String> result = strings.stream()
.sorted()
.collect(Collector.toList()) ;
Un

ème
2

exemple

Trions une liste de chaîne de caractères
// un jour un petit malin change l’implémentation
SortedSet<String> strings = new TreeSet<>() ;
// on remplit la liste
// et plus loin dans le code on a ça :
List<String> result = strings.stream()
.sorted()
.collect(Collector.toList()) ;

Dans ce cas le code de tri n’est plus exécuté !
Opérations stateless / statefull
Opérations Stateless / statefull
Certaines opérations sont stateless :
persons.stream().map(p -> p.getAge()) ;

Cela signifie que l’on n’a pas besoin de plus d’information
que ce qui est contenu dans p
Opérations stateless / statefull
Opérations Stateless / statefull
Certaines opérations sont stateless :
persons.stream().map(p -> p.getAge()) ;

Pas le cas de toutes les opérations
stream.limit(10_000_000) ; // select les 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
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()) ;
}

Soooo Java 7…
Exemple
Trions un tableau de String
Random rand = new Random() ;
Stream<String> stream =
Stream.generate(
() ->
Long.toHexString(rand.nextLong())
) ;

Meilleur ?
Exemple
Trions un tableau de String
// Random rand = new Random() ;
Stream<String> stream =
Stream.generate(
() ->
Long.toHexString(ThreadLocalRandom.current().nextLong())
) ;

Meilleur !
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
Example
Trions un tableau de String
// other way
Stream<String> stream =
ThreadLocalRandom
.current()
.longs()
.mapToObj(Long::toHexString)
.limit(10_000_000)
.sorted() ;

Opérations
intermédiares !

Object [] sorted = stream.toArray() ;

T = 14 s
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()
Stream<String> s = strings.parallelStream() ;

2) Appeler parallel() sur un stream existant
Stream<String> s = strings.stream().parallel() ;
Peut-on choisir le nombre cœurs ?
La réponse est non
Peut-on choisir le nombre cœurs ?
La réponse est non
Mais… en a-t-on vraiment besoin ?
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 :
persons.stream().limit(10_000_000) ;

« retourne les premiers 10M éléments »
Paralléliser est-il aussi simple ?
Exemple 1 :
persons.parallelStream().limit(10_000_000) ;

« retourne les premiers 10M éléments »
Paralléliser est-il aussi simple ?
Exemple 1 :
persons.parallelStream().limit(10_000_000) ;

« retourne les premiers 10M éléments »

Comment peut-on tracer que les éléments sont les
premiers sur un CPU multicœur ?
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

Code 1 (for)
Code 2 (limit)
Code 3 (longs)

Série
270 ms
310 ms
250 ms

Parallèle
Paralléliser est-il aussi simple ?
Exemple 1 : performances

Code 1 (for)
Code 2 (limit)
Code 3 (longs)

Série
270 ms
310 ms
250 ms

Parallèle

500 ms
320 ms
Paralléliser est-il aussi simple ?
Exemple 2 :
Stream s3 = Stream.concat(stream1, stream2) ;

« retourne un Stream composé des éléments du premier
Stream, puis des éléments du second »
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
Qu’est-ce qu’une réduction ?
2 types de réduction :
1) La réduction

« A reduction operation (also called a fold) takes a
sequence of input elements and combines them
into a single summary result by repeated
application of a combining operation »
Qu’est-ce qu’une réduction ?
2 types de réduction :
2) La réduction mutable

« A mutable reduction operation accumulates
input elements into a mutable result container,
such as a Collection or StringBuilder, as it
processes the elements in the stream »
Une réduction simple
La somme des âges
// map / filter / reduce pattern on collections
int sum = persons.stream()
.map(p -> p.getAge())
.filter(a -> a > 20)
.reduce(0, (a1, a2) -> a1 + a2) ;
Une réduction simple
Ca serait bien de pouvoir écrire :
// map / filter / reduce pattern on collections
int sum = persons.stream()
.map(p -> p.getAge())
.filter(a -> a > 20)
.sum() ;

Mais sum() n’est pas définie sur Stream<T>
Que voudrait dire « additionner des personnes » ?
Une réduction simple
Ca serait bien de pouvoir écrire :
// map / filter / reduce pattern on collections
int sum = persons.stream()
.map(p -> p.getAge())
.filter(a -> a > 20)
.sum() ;

Mais sum() n’est pas définie sur Stream<T>
Mais il y a une méthode sum() sur IntStream !
Une réduction simple
2ème version :
// map / filter / reduce pattern on collections
int sum = persons.stream()
.map(Person::getAge)
.filter(a -> a > 20)
.mapToInt(Integer::intValue)
.sum() ;

Résultat pour une liste vide : 0
Une réduction simple
2ème version (encore meilleure) :
// map / filter / reduce pattern on collections
int sum = persons.stream()
.mapToInt(Person::getAge)
.filter(a -> a > 20)
// .mapToInt(Integer::intValue)
.sum() ;

Résultat pour une liste vide : 0
Une réduction simple
Qu’en est-il de min() et de max() ?
// map / filter / reduce pattern on collections
....... = persons.stream()
.mapToInt(Person::getAge)
.filter(a -> a > 20)
.max() ;

Quelle valeur par défaut pour 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
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() ?
// map / filter / reduce pattern on collections
....... = persons.stream()
.mapToInt(Person::getAge)
.filter(a -> a > 20)
.max() ;

Si c’est int, la valeur par défaut sera 0…
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()
- summaryStatistics()
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)
Mutable reductions
La forme générale a donc besoin de 3 objets :
- un supplier : construit une instance du container

Supplier<ArrayList<String>> supplier = () -> new ArrayList<String>() ;
Mutable reductions
La forme générale a donc besoin de 3 objets :
- un supplier : construit une instance du container
- un accumulateur : ajoute un élément au container

BiConsumer<ArrayList<String>, ? super String> accumulator =
(suppliedList, s) -> suppliedList.add(s) ;
Mutable reductions
La forme générale a donc besoin de 3 objets :
- un supplier : construit une instance du container
- un accumulateur : ajoute un élément au container
- un combiner : fusionne deux containers

BiConsumer<ArrayList<String>, ArrayList<String>> combiner =
(supplied1, supplied2) -> supplied1.addAll(supplied2) ;
Mutable reductions : exemple 1
D’où le code :
ArrayList<String> strings =
stream
.map(Object::toString)
.collect(
() -> new ArrayList<String>(), // the supplier
(suppliedList, s) -> suppliedList.add(s), // the accumulator
(supplied1, supplied2) -> supplied1.addAll(supplied2) // the combiner
) ;
Mutable reductions : exemple 1
D’où le code :
ArrayList<String> strings =
stream
.map(Object::toString)
.collect(
ArrayList::new,
// the supplier
ArrayList::add,
// the accumulator
ArrayList::addAll // the combiner
) ;
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
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 nom 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
Optional<Person> optionalPerson = persons
.stream()
.collect(
Collectors.maxBy(
Comparator.comparing(Person::getAge)) ;

Bonus : une API Comparator
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
Map<Integer, Long> map =
persons
.stream()
.collect(
Collectors.groupingBy(Person::getAge, Collectors.counting())
) ;

Donne le nombre de personnes par âge
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<Boolean, List<Person>> map =
persons
.stream()
.collect(
Collectors.partitioningBy(p -> p.getAge() > 20)
) ;

map.get(TRUE) retourne la liste des personnes de plus de
20 ans
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
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
) ;

Dans ce cas « Map::entrySet » est un finisher
Quelques exemples réels
er
1

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()) ;
er
1

exemple
Un stream de movies

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()) ;
er
1

exemple
Construction d’une map
année / # de films

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()) ;
er
1

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
er
1

exemple
Et déterminer la plus
grande valeur

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()) ;
er
1

exemple
Retourne l’année qui a
vu le plus grand
nombre de films

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()) ;
Remarques sur parallel()
Traitement parallèle
Deux façons de le faire :
- créer un stream parallèle d’entrée
- Appeler parallel() sur un stream donné, on peut aussi
appeler sequential()
Quand une opération terminale est appelée, l’ensemble
des opérations est exécuté en parallèle ou pas, en fonction
du mode du stream
Les choses qui ne marchent pas
Certaines opérations ne donnent pas des résultats
reproductibles en parallèle, ex : findAny()
On ne doit pas modifier la source durant le traitement, si on
le fait les résultats ne sont pas prévisibles, même si la
source est une collection concurrente
Les choses qui marchent pas, mais…
Le traitement parallèle doit être le moins contraint possible
pour être efficace
- ORDERED est une contrainte coûteuse
- collect() doit utiliser des structures concurrentes
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
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
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 travail
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 travail
- 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 !
JDK 8, lambdas, streams, collectors - Bretagne Tour
JDK 8, lambdas, streams, collectors - Bretagne Tour

Weitere ähnliche Inhalte

Was ist angesagt?

Interface fonctionnelle, Lambda expression, méthode par défaut, référence de...
Interface fonctionnelle, Lambda expression, méthode par défaut,  référence de...Interface fonctionnelle, Lambda expression, méthode par défaut,  référence de...
Interface fonctionnelle, Lambda expression, méthode par défaut, référence de...MICHRAFY MUSTAFA
 
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 bateauJosé Paumard
 
Retours sur java 8 devoxx fr 2016
Retours sur java 8 devoxx fr 2016Retours sur java 8 devoxx fr 2016
Retours sur java 8 devoxx fr 2016Jean-Michel Doudoux
 
Techday Arrow Group: Java 8
Techday Arrow Group: Java 8Techday Arrow Group: Java 8
Techday Arrow Group: Java 8Arrow Group
 
Java (8) eXperiments - DevoxxFR 2016
Java (8) eXperiments - DevoxxFR 2016Java (8) eXperiments - DevoxxFR 2016
Java (8) eXperiments - DevoxxFR 2016François Sarradin
 
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 mouvementsDidier Plaindoux
 
Javascript : fondamentaux et OOP
Javascript : fondamentaux et OOPJavascript : fondamentaux et OOP
Javascript : fondamentaux et OOPJean-Pierre Vincent
 
Scala : programmation fonctionnelle
Scala : programmation fonctionnelleScala : programmation fonctionnelle
Scala : programmation fonctionnelleMICHRAFY MUSTAFA
 
Programmation fonctionnelle
Programmation fonctionnelleProgrammation fonctionnelle
Programmation fonctionnelleGeeks Anonymes
 
Android Optimisations Greendroid
Android Optimisations GreendroidAndroid Optimisations Greendroid
Android Optimisations GreendroidGDG Nantes
 
Javascript pour les développeurs Java : quels sont les pièges à éviter ?
Javascript pour les développeurs Java : quels sont les pièges à éviter ?Javascript pour les développeurs Java : quels sont les pièges à éviter ?
Javascript pour les développeurs Java : quels sont les pièges à éviter ?FlorianBoulay
 
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...Normandy JUG
 
Librairies Java qui changent la vie
Librairies Java qui changent la vieLibrairies Java qui changent la vie
Librairies Java qui changent la viecluelessjoe
 
Chapitre8: Collections et Enumerations En Java
Chapitre8: Collections et Enumerations En JavaChapitre8: Collections et Enumerations En Java
Chapitre8: Collections et Enumerations En JavaAziz Darouichi
 
Présentation Groovy
Présentation GroovyPrésentation Groovy
Présentation Groovyguest6e3bed
 
Introduction à l'analyse de réseaux avec R
Introduction à l'analyse de réseaux avec RIntroduction à l'analyse de réseaux avec R
Introduction à l'analyse de réseaux avec RLaurent Beauguitte
 
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 PinbaPatrick Allaert
 

Was ist angesagt? (20)

Interface fonctionnelle, Lambda expression, méthode par défaut, référence de...
Interface fonctionnelle, Lambda expression, méthode par défaut,  référence de...Interface fonctionnelle, Lambda expression, méthode par défaut,  référence de...
Interface fonctionnelle, Lambda expression, méthode par défaut, référence de...
 
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
 
Retours sur java 8 devoxx fr 2016
Retours sur java 8 devoxx fr 2016Retours sur java 8 devoxx fr 2016
Retours sur java 8 devoxx fr 2016
 
Techday Arrow Group: Java 8
Techday Arrow Group: Java 8Techday Arrow Group: Java 8
Techday Arrow Group: Java 8
 
Java (8) eXperiments - DevoxxFR 2016
Java (8) eXperiments - DevoxxFR 2016Java (8) eXperiments - DevoxxFR 2016
Java (8) eXperiments - DevoxxFR 2016
 
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
 
Javascript : fondamentaux et OOP
Javascript : fondamentaux et OOPJavascript : fondamentaux et OOP
Javascript : fondamentaux et OOP
 
Programmation Fonctionnelle
Programmation FonctionnelleProgrammation Fonctionnelle
Programmation Fonctionnelle
 
Scala : programmation fonctionnelle
Scala : programmation fonctionnelleScala : programmation fonctionnelle
Scala : programmation fonctionnelle
 
Programmation fonctionnelle
Programmation fonctionnelleProgrammation fonctionnelle
Programmation fonctionnelle
 
Android Optimisations Greendroid
Android Optimisations GreendroidAndroid Optimisations Greendroid
Android Optimisations Greendroid
 
Javascript pour les développeurs Java : quels sont les pièges à éviter ?
Javascript pour les développeurs Java : quels sont les pièges à éviter ?Javascript pour les développeurs Java : quels sont les pièges à éviter ?
Javascript pour les développeurs Java : quels sont les pièges à éviter ?
 
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...
 
Librairies Java qui changent la vie
Librairies Java qui changent la vieLibrairies Java qui changent la vie
Librairies Java qui changent la vie
 
Chapitre8: Collections et Enumerations En Java
Chapitre8: Collections et Enumerations En JavaChapitre8: Collections et Enumerations En Java
Chapitre8: Collections et Enumerations En Java
 
Présentation Groovy
Présentation GroovyPrésentation Groovy
Présentation Groovy
 
Introduction à l'analyse de réseaux avec R
Introduction à l'analyse de réseaux avec RIntroduction à l'analyse de réseaux avec R
Introduction à l'analyse de réseaux avec R
 
Java SE 7
Java SE 7Java SE 7
Java SE 7
 
Initiation r
Initiation rInitiation r
Initiation r
 
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
 

Ähnlich wie JDK 8, lambdas, streams, collectors - Bretagne Tour

Datamapper L Orm Dans Rails 3
Datamapper L Orm Dans Rails 3Datamapper L Orm Dans Rails 3
Datamapper L Orm Dans Rails 3Cyril Mougel
 
201303 - Java8
201303 - Java8201303 - Java8
201303 - Java8lyonjug
 
201305 - Lambda by R. Forax
201305 - Lambda by R. Forax201305 - Lambda by R. Forax
201305 - Lambda by R. Foraxlyonjug
 
TP3: Comportement Temps Réel de l'Agent Perception
TP3: Comportement Temps Réel de l'Agent PerceptionTP3: Comportement Temps Réel de l'Agent Perception
TP3: Comportement Temps Réel de l'Agent PerceptionSaid Benaissa
 
Cours langage c
Cours langage cCours langage c
Cours langage ccoursuniv
 
PL LSQL.pptx
PL LSQL.pptxPL LSQL.pptx
PL LSQL.pptxMaNl13
 
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 pratiqueVladyslav Riabchenko
 
MyBatis, une alternative à JPA.
MyBatis, une alternative à JPA.MyBatis, une alternative à JPA.
MyBatis, une alternative à JPA.Kokou Gaglo
 
Lect14 dev2
Lect14 dev2Lect14 dev2
Lect14 dev2moisko
 
09 big data mapreduce
09 big data mapreduce09 big data mapreduce
09 big data mapreducePatrick Bury
 
Cours de C++, en français, 2002 - Cours 3.5
Cours de C++, en français, 2002 - Cours 3.5Cours de C++, en français, 2002 - Cours 3.5
Cours de C++, en français, 2002 - Cours 3.5Laurent BUNIET
 
09 big data mapreduce
09 big data mapreduce09 big data mapreduce
09 big data mapreducePatrick Bury
 
Tp1 compte rendu en langage c
Tp1 compte rendu en langage cTp1 compte rendu en langage c
Tp1 compte rendu en langage cEbrima NJIE
 
Chap 1 Initiation.pptx
Chap 1 Initiation.pptxChap 1 Initiation.pptx
Chap 1 Initiation.pptxolfaharrabi2
 
Partie1 TypeScript
Partie1 TypeScriptPartie1 TypeScript
Partie1 TypeScriptHabib Ayad
 

Ähnlich wie JDK 8, lambdas, streams, collectors - Bretagne Tour (20)

Datamapper L Orm Dans Rails 3
Datamapper L Orm Dans Rails 3Datamapper L Orm Dans Rails 3
Datamapper L Orm Dans Rails 3
 
201303 - Java8
201303 - Java8201303 - Java8
201303 - Java8
 
201305 - Lambda by R. Forax
201305 - Lambda by R. Forax201305 - Lambda by R. Forax
201305 - Lambda by R. Forax
 
TP3: Comportement Temps Réel de l'Agent Perception
TP3: Comportement Temps Réel de l'Agent PerceptionTP3: Comportement Temps Réel de l'Agent Perception
TP3: Comportement Temps Réel de l'Agent Perception
 
TAD (1).pptx
TAD (1).pptxTAD (1).pptx
TAD (1).pptx
 
Php4 Mysql
Php4 MysqlPhp4 Mysql
Php4 Mysql
 
Cours langage c
Cours langage cCours langage c
Cours langage c
 
PL LSQL.pptx
PL LSQL.pptxPL LSQL.pptx
PL LSQL.pptx
 
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
 
Chap1_Entrees_Sorties.pptx
Chap1_Entrees_Sorties.pptxChap1_Entrees_Sorties.pptx
Chap1_Entrees_Sorties.pptx
 
MyBatis, une alternative à JPA.
MyBatis, une alternative à JPA.MyBatis, une alternative à JPA.
MyBatis, une alternative à JPA.
 
Lect14 dev2
Lect14 dev2Lect14 dev2
Lect14 dev2
 
09 big data mapreduce
09 big data mapreduce09 big data mapreduce
09 big data mapreduce
 
Cours de C++, en français, 2002 - Cours 3.5
Cours de C++, en français, 2002 - Cours 3.5Cours de C++, en français, 2002 - Cours 3.5
Cours de C++, en français, 2002 - Cours 3.5
 
Chapitre 04 : les fonctions
Chapitre 04 : les fonctionsChapitre 04 : les fonctions
Chapitre 04 : les fonctions
 
09 big data mapreduce
09 big data mapreduce09 big data mapreduce
09 big data mapreduce
 
Dijkstra kshortest
Dijkstra kshortestDijkstra kshortest
Dijkstra kshortest
 
Tp1 compte rendu en langage c
Tp1 compte rendu en langage cTp1 compte rendu en langage c
Tp1 compte rendu en langage c
 
Chap 1 Initiation.pptx
Chap 1 Initiation.pptxChap 1 Initiation.pptx
Chap 1 Initiation.pptx
 
Partie1 TypeScript
Partie1 TypeScriptPartie1 TypeScript
Partie1 TypeScript
 

Mehr von José Paumard

Loom Virtual Threads in the JDK 19
Loom Virtual Threads in the JDK 19Loom Virtual Threads in the JDK 19
Loom Virtual Threads in the JDK 19José Paumard
 
From Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdfFrom Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdfJosé Paumard
 
The Future of Java: Records, Sealed Classes and Pattern Matching
The Future of Java: Records, Sealed Classes and Pattern MatchingThe Future of Java: Records, Sealed Classes and Pattern Matching
The Future of Java: Records, Sealed Classes and Pattern MatchingJosé Paumard
 
Deep Dive Java 17 Devoxx UK
Deep Dive Java 17 Devoxx UKDeep Dive Java 17 Devoxx UK
Deep Dive Java 17 Devoxx UKJosé Paumard
 
Designing functional and fluent API: application to some GoF patterns
Designing functional and fluent API: application to some GoF patternsDesigning functional and fluent API: application to some GoF patterns
Designing functional and fluent API: application to some GoF patternsJosé Paumard
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of FlatteryJosé Paumard
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of FlatteryJosé Paumard
 
Designing functional and fluent API: example of the Visitor Pattern
Designing functional and fluent API: example of the Visitor PatternDesigning functional and fluent API: example of the Visitor Pattern
Designing functional and fluent API: example of the Visitor PatternJosé Paumard
 
Construire son JDK en 10 étapes
Construire son JDK en 10 étapesConstruire son JDK en 10 étapes
Construire son JDK en 10 étapesJosé Paumard
 
Java Keeps Throttling Up!
Java Keeps Throttling Up!Java Keeps Throttling Up!
Java Keeps Throttling Up!José Paumard
 
Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2José Paumard
 
Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1José Paumard
 
Asynchronous Systems with Fn Flow
Asynchronous Systems with Fn FlowAsynchronous Systems with Fn Flow
Asynchronous Systems with Fn FlowJosé Paumard
 
JAX-RS and CDI Bike the (Reactive) Bridge
JAX-RS and CDI Bike the (Reactive) BridgeJAX-RS and CDI Bike the (Reactive) Bridge
JAX-RS and CDI Bike the (Reactive) BridgeJosé Paumard
 
Collectors in the Wild
Collectors in the WildCollectors in the Wild
Collectors in the WildJosé Paumard
 
JAX RS and CDI bike the reactive bridge
JAX RS and CDI bike the reactive bridgeJAX RS and CDI bike the reactive bridge
JAX RS and CDI bike the reactive bridgeJosé Paumard
 
Linked to ArrayList: the full story
Linked to ArrayList: the full storyLinked to ArrayList: the full story
Linked to ArrayList: the full storyJosé Paumard
 

Mehr von José Paumard (20)

Loom Virtual Threads in the JDK 19
Loom Virtual Threads in the JDK 19Loom Virtual Threads in the JDK 19
Loom Virtual Threads in the JDK 19
 
From Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdfFrom Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdf
 
The Future of Java: Records, Sealed Classes and Pattern Matching
The Future of Java: Records, Sealed Classes and Pattern MatchingThe Future of Java: Records, Sealed Classes and Pattern Matching
The Future of Java: Records, Sealed Classes and Pattern Matching
 
Deep Dive Java 17 Devoxx UK
Deep Dive Java 17 Devoxx UKDeep Dive Java 17 Devoxx UK
Deep Dive Java 17 Devoxx UK
 
Designing functional and fluent API: application to some GoF patterns
Designing functional and fluent API: application to some GoF patternsDesigning functional and fluent API: application to some GoF patterns
Designing functional and fluent API: application to some GoF patterns
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of Flattery
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of Flattery
 
Designing functional and fluent API: example of the Visitor Pattern
Designing functional and fluent API: example of the Visitor PatternDesigning functional and fluent API: example of the Visitor Pattern
Designing functional and fluent API: example of the Visitor Pattern
 
Construire son JDK en 10 étapes
Construire son JDK en 10 étapesConstruire son JDK en 10 étapes
Construire son JDK en 10 étapes
 
Java Keeps Throttling Up!
Java Keeps Throttling Up!Java Keeps Throttling Up!
Java Keeps Throttling Up!
 
Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2
 
Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1
 
Asynchronous Systems with Fn Flow
Asynchronous Systems with Fn FlowAsynchronous Systems with Fn Flow
Asynchronous Systems with Fn Flow
 
Java Full Throttle
Java Full ThrottleJava Full Throttle
Java Full Throttle
 
JAX-RS and CDI Bike the (Reactive) Bridge
JAX-RS and CDI Bike the (Reactive) BridgeJAX-RS and CDI Bike the (Reactive) Bridge
JAX-RS and CDI Bike the (Reactive) Bridge
 
Collectors in the Wild
Collectors in the WildCollectors in the Wild
Collectors in the Wild
 
Streams in the wild
Streams in the wildStreams in the wild
Streams in the wild
 
JAX RS and CDI bike the reactive bridge
JAX RS and CDI bike the reactive bridgeJAX RS and CDI bike the reactive bridge
JAX RS and CDI bike the reactive bridge
 
Free your lambdas
Free your lambdasFree your lambdas
Free your lambdas
 
Linked to ArrayList: the full story
Linked to ArrayList: the full storyLinked to ArrayList: the full story
Linked to ArrayList: the full story
 

Kürzlich hochgeladen

Cours SE Gestion des périphériques - IG IPSET
Cours SE Gestion des périphériques - IG IPSETCours SE Gestion des périphériques - IG IPSET
Cours SE Gestion des périphériques - IG IPSETMedBechir
 
Bernard Réquichot.pptx Peintre français
Bernard Réquichot.pptx   Peintre françaisBernard Réquichot.pptx   Peintre français
Bernard Réquichot.pptx Peintre françaisTxaruka
 
Bibdoc 2024 - Les maillons de la chaine du livre face aux enjeux écologiques.pdf
Bibdoc 2024 - Les maillons de la chaine du livre face aux enjeux écologiques.pdfBibdoc 2024 - Les maillons de la chaine du livre face aux enjeux écologiques.pdf
Bibdoc 2024 - Les maillons de la chaine du livre face aux enjeux écologiques.pdfBibdoc 37
 
LA MONTÉE DE L'ÉDUCATION DANS LE MONDE DE LA PRÉHISTOIRE À L'ÈRE CONTEMPORAIN...
LA MONTÉE DE L'ÉDUCATION DANS LE MONDE DE LA PRÉHISTOIRE À L'ÈRE CONTEMPORAIN...LA MONTÉE DE L'ÉDUCATION DANS LE MONDE DE LA PRÉHISTOIRE À L'ÈRE CONTEMPORAIN...
LA MONTÉE DE L'ÉDUCATION DANS LE MONDE DE LA PRÉHISTOIRE À L'ÈRE CONTEMPORAIN...Faga1939
 
le present des verbes reguliers -er.pptx
le present des verbes reguliers -er.pptxle present des verbes reguliers -er.pptx
le present des verbes reguliers -er.pptxmmatar2
 
Bibdoc 2024 - Ecologie du livre et creation de badge.pdf
Bibdoc 2024 - Ecologie du livre et creation de badge.pdfBibdoc 2024 - Ecologie du livre et creation de badge.pdf
Bibdoc 2024 - Ecologie du livre et creation de badge.pdfBibdoc 37
 
Présentation_ Didactique 1_SVT (S4) complet.pptx
Présentation_ Didactique 1_SVT (S4) complet.pptxPrésentation_ Didactique 1_SVT (S4) complet.pptx
Présentation_ Didactique 1_SVT (S4) complet.pptxrababouerdighi
 
SciencesPo_Aix_InnovationPédagogique_Atelier_EtudiantActeur.pdf
SciencesPo_Aix_InnovationPédagogique_Atelier_EtudiantActeur.pdfSciencesPo_Aix_InnovationPédagogique_Atelier_EtudiantActeur.pdf
SciencesPo_Aix_InnovationPédagogique_Atelier_EtudiantActeur.pdfSKennel
 
SciencesPo_Aix_InnovationPédagogique_Atelier_IA.pdf
SciencesPo_Aix_InnovationPédagogique_Atelier_IA.pdfSciencesPo_Aix_InnovationPédagogique_Atelier_IA.pdf
SciencesPo_Aix_InnovationPédagogique_Atelier_IA.pdfSKennel
 
SciencesPo_Aix_InnovationPédagogique_Atelier_FormationRecherche.pdf
SciencesPo_Aix_InnovationPédagogique_Atelier_FormationRecherche.pdfSciencesPo_Aix_InnovationPédagogique_Atelier_FormationRecherche.pdf
SciencesPo_Aix_InnovationPédagogique_Atelier_FormationRecherche.pdfSKennel
 
Cours SE Le système Linux : La ligne de commande bash - IG IPSET
Cours SE Le système Linux : La ligne de commande bash - IG IPSETCours SE Le système Linux : La ligne de commande bash - IG IPSET
Cours SE Le système Linux : La ligne de commande bash - IG IPSETMedBechir
 
Saint Georges, martyr, et la lègend du dragon.pptx
Saint Georges, martyr, et la lègend du dragon.pptxSaint Georges, martyr, et la lègend du dragon.pptx
Saint Georges, martyr, et la lègend du dragon.pptxMartin M Flynn
 
Principe de fonctionnement d'un moteur 4 temps
Principe de fonctionnement d'un moteur 4 tempsPrincipe de fonctionnement d'un moteur 4 temps
Principe de fonctionnement d'un moteur 4 tempsRajiAbdelghani
 
SciencesPo_Aix_InnovationPédagogique_Bilan.pdf
SciencesPo_Aix_InnovationPédagogique_Bilan.pdfSciencesPo_Aix_InnovationPédagogique_Bilan.pdf
SciencesPo_Aix_InnovationPédagogique_Bilan.pdfSKennel
 
Evaluation du systeme d'Education. Marocpptx
Evaluation du systeme d'Education. MarocpptxEvaluation du systeme d'Education. Marocpptx
Evaluation du systeme d'Education. MarocpptxAsmaa105193
 
Annie Ernaux Extérieurs. pptx. Exposition basée sur un livre .
Annie   Ernaux  Extérieurs. pptx. Exposition basée sur un livre .Annie   Ernaux  Extérieurs. pptx. Exposition basée sur un livre .
Annie Ernaux Extérieurs. pptx. Exposition basée sur un livre .Txaruka
 
Presentation de la plateforme Moodle - avril 2024
Presentation de la plateforme Moodle - avril 2024Presentation de la plateforme Moodle - avril 2024
Presentation de la plateforme Moodle - avril 2024Gilles Le Page
 
Zotero avancé - support de formation doctorants SHS 2024
Zotero avancé - support de formation doctorants SHS 2024Zotero avancé - support de formation doctorants SHS 2024
Zotero avancé - support de formation doctorants SHS 2024Alain Marois
 
SciencesPo_Aix_InnovationPédagogique_Conférence_SK.pdf
SciencesPo_Aix_InnovationPédagogique_Conférence_SK.pdfSciencesPo_Aix_InnovationPédagogique_Conférence_SK.pdf
SciencesPo_Aix_InnovationPédagogique_Conférence_SK.pdfSKennel
 

Kürzlich hochgeladen (20)

Cours SE Gestion des périphériques - IG IPSET
Cours SE Gestion des périphériques - IG IPSETCours SE Gestion des périphériques - IG IPSET
Cours SE Gestion des périphériques - IG IPSET
 
Bernard Réquichot.pptx Peintre français
Bernard Réquichot.pptx   Peintre françaisBernard Réquichot.pptx   Peintre français
Bernard Réquichot.pptx Peintre français
 
Bibdoc 2024 - Les maillons de la chaine du livre face aux enjeux écologiques.pdf
Bibdoc 2024 - Les maillons de la chaine du livre face aux enjeux écologiques.pdfBibdoc 2024 - Les maillons de la chaine du livre face aux enjeux écologiques.pdf
Bibdoc 2024 - Les maillons de la chaine du livre face aux enjeux écologiques.pdf
 
LA MONTÉE DE L'ÉDUCATION DANS LE MONDE DE LA PRÉHISTOIRE À L'ÈRE CONTEMPORAIN...
LA MONTÉE DE L'ÉDUCATION DANS LE MONDE DE LA PRÉHISTOIRE À L'ÈRE CONTEMPORAIN...LA MONTÉE DE L'ÉDUCATION DANS LE MONDE DE LA PRÉHISTOIRE À L'ÈRE CONTEMPORAIN...
LA MONTÉE DE L'ÉDUCATION DANS LE MONDE DE LA PRÉHISTOIRE À L'ÈRE CONTEMPORAIN...
 
le present des verbes reguliers -er.pptx
le present des verbes reguliers -er.pptxle present des verbes reguliers -er.pptx
le present des verbes reguliers -er.pptx
 
Bibdoc 2024 - Ecologie du livre et creation de badge.pdf
Bibdoc 2024 - Ecologie du livre et creation de badge.pdfBibdoc 2024 - Ecologie du livre et creation de badge.pdf
Bibdoc 2024 - Ecologie du livre et creation de badge.pdf
 
Présentation_ Didactique 1_SVT (S4) complet.pptx
Présentation_ Didactique 1_SVT (S4) complet.pptxPrésentation_ Didactique 1_SVT (S4) complet.pptx
Présentation_ Didactique 1_SVT (S4) complet.pptx
 
SciencesPo_Aix_InnovationPédagogique_Atelier_EtudiantActeur.pdf
SciencesPo_Aix_InnovationPédagogique_Atelier_EtudiantActeur.pdfSciencesPo_Aix_InnovationPédagogique_Atelier_EtudiantActeur.pdf
SciencesPo_Aix_InnovationPédagogique_Atelier_EtudiantActeur.pdf
 
SciencesPo_Aix_InnovationPédagogique_Atelier_IA.pdf
SciencesPo_Aix_InnovationPédagogique_Atelier_IA.pdfSciencesPo_Aix_InnovationPédagogique_Atelier_IA.pdf
SciencesPo_Aix_InnovationPédagogique_Atelier_IA.pdf
 
SciencesPo_Aix_InnovationPédagogique_Atelier_FormationRecherche.pdf
SciencesPo_Aix_InnovationPédagogique_Atelier_FormationRecherche.pdfSciencesPo_Aix_InnovationPédagogique_Atelier_FormationRecherche.pdf
SciencesPo_Aix_InnovationPédagogique_Atelier_FormationRecherche.pdf
 
Cours SE Le système Linux : La ligne de commande bash - IG IPSET
Cours SE Le système Linux : La ligne de commande bash - IG IPSETCours SE Le système Linux : La ligne de commande bash - IG IPSET
Cours SE Le système Linux : La ligne de commande bash - IG IPSET
 
Saint Georges, martyr, et la lègend du dragon.pptx
Saint Georges, martyr, et la lègend du dragon.pptxSaint Georges, martyr, et la lègend du dragon.pptx
Saint Georges, martyr, et la lègend du dragon.pptx
 
Principe de fonctionnement d'un moteur 4 temps
Principe de fonctionnement d'un moteur 4 tempsPrincipe de fonctionnement d'un moteur 4 temps
Principe de fonctionnement d'un moteur 4 temps
 
SciencesPo_Aix_InnovationPédagogique_Bilan.pdf
SciencesPo_Aix_InnovationPédagogique_Bilan.pdfSciencesPo_Aix_InnovationPédagogique_Bilan.pdf
SciencesPo_Aix_InnovationPédagogique_Bilan.pdf
 
Evaluation du systeme d'Education. Marocpptx
Evaluation du systeme d'Education. MarocpptxEvaluation du systeme d'Education. Marocpptx
Evaluation du systeme d'Education. Marocpptx
 
Annie Ernaux Extérieurs. pptx. Exposition basée sur un livre .
Annie   Ernaux  Extérieurs. pptx. Exposition basée sur un livre .Annie   Ernaux  Extérieurs. pptx. Exposition basée sur un livre .
Annie Ernaux Extérieurs. pptx. Exposition basée sur un livre .
 
Presentation de la plateforme Moodle - avril 2024
Presentation de la plateforme Moodle - avril 2024Presentation de la plateforme Moodle - avril 2024
Presentation de la plateforme Moodle - avril 2024
 
DO PALÁCIO À ASSEMBLEIA .
DO PALÁCIO À ASSEMBLEIA                 .DO PALÁCIO À ASSEMBLEIA                 .
DO PALÁCIO À ASSEMBLEIA .
 
Zotero avancé - support de formation doctorants SHS 2024
Zotero avancé - support de formation doctorants SHS 2024Zotero avancé - support de formation doctorants SHS 2024
Zotero avancé - support de formation doctorants SHS 2024
 
SciencesPo_Aix_InnovationPédagogique_Conférence_SK.pdf
SciencesPo_Aix_InnovationPédagogique_Conférence_SK.pdfSciencesPo_Aix_InnovationPédagogique_Conférence_SK.pdf
SciencesPo_Aix_InnovationPédagogique_Conférence_SK.pdf
 

JDK 8, lambdas, streams, collectors - Bretagne Tour

  • 1. JDK 8 & Lambdas Lambdas, Streams, Collectors
  • 2.
  • 3.
  • 4. Pourquoi ont-ils été introduits ?
  • 5. Pourquoi ont-ils été introduits ? Pourquoi sont-ils si importants ?
  • 6. Pourquoi ont-ils été introduits ? Pourquoi sont-ils si importants ? Comment vont-ils changer nos habitudes de programmation ?
  • 7.
  • 8.
  • 9.
  • 11. Introduisons les lambdas sur un exemple simple
  • 12. Un exemple très simple public class Person { Un bon vieux bean private String name ; private int age ; // constructors // getters / setters } List<Person> list = new ArrayList<>() ; … et une bonne vieille liste
  • 13. Calculons la moyenne des âges des personnes 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() ; }
  • 14. Plus dur : pour les personnes de plus de 20 ans 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 ; }
  • 15. Plus dur : pour les personnes de plus de 20 ans 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 ; } « programmation impérative »
  • 16. … pas une obligation ! select avg(age) from Person where age > 20 Ici on décrit le résultat
  • 17. … pas une obligation ! select avg(age) from Person where age > 20 © SQL 1974 Ici on décrit le résultat Dans ce cas la base de données mène le calcul comme elle l’entend
  • 18. map Person age 1ère étape : mapping age > 20 sum
  • 19. map Person age age > 20 1ère étape : mapping Mapping : - prend une liste d’un type donné - retourne une liste d’un autre type - possède le même nombre d’éléments sum
  • 20. map Person filter age 2ème étape : filtrage age > 20 sum
  • 21. map Person filter age age > 20 2ème étape : filtrage Filtrage : - prend une liste d’un type donné - retourne une liste du même type - mais avec moins d’éléments sum
  • 22. map Person filter age 3ème étape : réduction reduce age > 20 sum
  • 23. map Person filter age reduce age > 20 sum 3ème étape : réduction Reduction : agrégation des éléments d’une liste dans un seul élément Ex : moyenne, somme, min, max, etc…
  • 25. 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) ; }
  • 26. La façon JDK 7 … et on crée une classe anonyme 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() ; } }
  • 27. La façon JDK 7 On peut faire la même chose pour le filtrage public interface Predicate<T> { public boolean filter(T t) ; }
  • 28. La façon JDK 7 On peut faire la même chose pour le filtrage public interface Predicate<T> { public boolean filter(T t) ; } AgePredicate predicate = new Predicate<Integer>() { public boolean filter(Integer i) { return i > 20 ; } }
  • 29. La façon JDK 7 Et enfin pour la réduction public interface Reducer<T> { public T reduce(T t1, T t2) ; }
  • 30. La façon JDK 7 Et enfin pour la réduction public interface Reducer<T> { public T reduce(T t1, T t2) ; } Reducer<Integer> reduction = new Reducer<Integer>() { public Integer reduce(Integer i1, Integer i2) { return i1 + i2 ; } }
  • 31. La façon JDK 7 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) ; }
  • 32. 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 ; } } }) ;
  • 33. 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 ; } } }) ;
  • 34. À la façon du JDK 8
  • 35. La façon du JDK 8 Prenons l’exemple du Mapper mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { return person.getAge() ; } }
  • 36. 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() ; } }
  • 37. 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 p.getAge() ; On prend } } person mapper = (Person person) ;
  • 38. 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() ; } } et… mapper = (Person person) -> ;
  • 39. 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() ; } } … on retourne mapper = (Person person) -> person.getAge() ; son âge
  • 40. 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() ;
  • 41. 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() ; Le compilateur reconnaît cette expression comme une implémentation du mapper
  • 42. Que se passe-t-il si … … il y a plus d’une ligne de code ? mapper = (Person person) -> { System.out.println("Mapping " + person) ; return person.getAge() ; } Accolades, un return explicite
  • 43. Que se passe-t-il si … …le type de retour est void ? consumer = (Person person) -> p.setAge(p.getAge() + 1) ;
  • 44. Que se passe-t-il si … …la méthode prend plus d’un argument ? reducer = (int i1, int i2) -> { return i1 + i2 ; } Ou : reducer = (int i1, int i2) -> i1 + i2 ;
  • 45. La façon du JDK 8 Comment le compilateur reconnaît-il l’implémentation du mapper ? mapper = (Person person) -> person.getAge() ;
  • 46. La façon du JDK 8 Comment le compilateur reconnaît-il l’implémentation du mapper ? mapper = (Person person) -> person.getAge() ; 1) Il ne faut qu’une méthode dans le mapper
  • 47. La façon du JDK 8 Comment le compilateur reconnaît-il l’implémentation du mapper ? mapper = (Person person) -> person.getAge() ; 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
  • 48. La façon du JDK 8 Comment le compilateur reconnaît-il l’implémentation du mapper ? mapper = (Person person) -> person.getAge() ; 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
  • 49. 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
  • 50. D’autres lambdas Et la plupart du temps, le compilateur reconnaît ceci : mapper = person -> person.getAge() ; // mapper filter = age -> age > 20 ; // filter reducer = (i1, i2) -> i1 + i2 ; // reducer Le type des paramètres peut être omis
  • 51. Une remarque sur la réduction Comment cela fonctionne-t-il réellement ?
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62. Réduction 2 exemples : Reducer r1 = (i1, i2) -> i1 + i2 ; // Ok Reducer r2 = (i1, i2) -> i1*i1 + i2*i2 ; // Oooops Attention : le résultat est toujours reproductible en série il ne l’est en général pas en parallèle
  • 63. Pour le moment Une expression lambda est une autre façon d’écrire des instances de classes anonymes
  • 64. Il y a d’autres syntaxes On peut écrire : mapper = person -> person.getAge() ; Mais on peut aussi écrire : mapper = Person::getAge ; // méthode non statique
  • 65. Il y a d’autres syntaxes On peut écrire : sum = (i1, i2) -> i1 + i2 ; sum = Integer::sum ; // méthode statique, nouvelle ! Ou encore : max = (i1, i2) -> i1 > i2 ? i1 : i2 ; max = Integer::max ; // méthode statique, nouvelle !
  • 66. Il y a d’autres syntaxes Encore un autre exemple : toLower = String::toLowerCase ; // !!!! NON NON NON !!!! toLowerFR = String::toLowerCase(Locale.FRANCE) ;
  • 67. Plus loin sur les lambdas
  • 68. Questions : Comment modéliser une expression lambda ?
  • 69. Questions : Comment modéliser une expression lambda ? Puis-je mettre une expression lambda dans une variable ?
  • 70. Questions : Comment modéliser une expression lambda ? Puis-je mettre une expression lambda dans une variable ? Un lambda est-il un objet ?
  • 71. Modélisation Un lambda = instance d’une « interface fonctionnelle » @FunctionalInterface public interface Consumer<T> { public void accept(T t) ; }
  • 72. Modélisation Un lambda = instance d’une « interface fonctionnelle » @FunctionalInterface public interface Consumer<T> { public void accept(T t) ; } - ne possède qu’une unique méthode
  • 73. Modélisation Un lambda = instance d’une « interface fonctionnelle » @FunctionalInterface public interface Consumer<T> { public void accept(T t) ; } - ne possède qu’une unique méthode - peut être annotée par @FunctionalInterface (optionnel)
  • 74. 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) ; } } ; Donc : Consumer<String> c = s -> System.out.println(s) ;
  • 75. 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) ; } } ; Question : qu’est-ce que s ? Donc : Consumer<String> c = s -> System.out.println(s) ;
  • 76. 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) ; } } ; Donc : Réponse : le compilateur infère qu’il s’agit d’un String Consumer<String> c = s -> System.out.println(s) ;
  • 77. Mettre un lambda dans une variable Question : peut-on écrire ce code ? int i = ... ; Consumer<String> c = new Consumer<String>() { @Override public void accept(String s) { System.out.println("i = " + i) ; } } ;
  • 78. Mettre un lambda dans une variable Question : peut-on écrire ce code ? int i = ... ; Consumer<String> c = new Consumer<String>() { @Override public void accept(String s) { System.out.println("i = " + i) ; } } ; JDK 7 : i doit être final
  • 79. Mettre un lambda dans une variable Question : peut-on écrire ce code ? int i = ... ; Consumer<String> c = new Consumer<String>() { @Override public void accept(String s) { System.out.println("i = " + i) ; } } ; JDK 8 : ce code compile
  • 80. Mettre un lambda dans une variable En revanche, ce code … int i = ... ; Consumer<String> c = new Consumer<String>() { @Override public void accept(String s) { System.out.println("i = " + i) ; } } ; i = i + 1 ; … ne compile pas
  • 81. Mettre un lambda dans une variable Raison : le compilateur infère que i est effectivement final final int i = ... ; Consumer<String> c = new Consumer<String>() { @Override public void accept(String s) { System.out.println("i = " + i) ; } } ; i = i + 1 ; // on ne peut pas modifier i
  • 82. Note au sujet de this JDK 7 : this est l’instance anonyme Consumer<String> c = new Consumer<String>() { @Override public void accept(String s) { System.out.println("this = " + this) ; } public String toString() { return "je suis dans c" ; } } ; Appeler accept() affiche donc « je suis dans c »
  • 83. Note au sujet de this JDK 8 : idem, accept() affiche « je suis dans c » Consumer<String> c = new Consumer<String>() { @Override public void accept(String s) { System.out.println("this = " + this) ; } public String toString() { return "je suis dans c" ; } } ; Mais …
  • 84. Note au sujet de this Un consommateur peut aussi s’écrire comme ça : Consumer<String> c = s -> System.out.println(this) ; Dans ce cas, this est l’instance englobante
  • 85. 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 ?
  • 86. 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) ;
  • 87. 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) ;
  • 88. 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
  • 89. Des lambdas à profusion : Java.util.functions
  • 90. Java.util.functions C’est dans ce package que sont les interfaces fonctionnelles Il y en a 43
  • 91. Java.util.functions Supplier Consumer / BiConsumer Function / BiFunction (UnaryOperator / BinaryOperator) Predicate / BiPredicate En plus des versions construites sur les types primitifs
  • 92. Supplier Un supplier fournit un objet public interface Supplier<T> { T get() ; }
  • 93. 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) ;
  • 94. BiConsumer Prend deux arguments au lieu d’un Peuvent être chaînés Versions types primitifs : - ObjIntConsumer - ObjLongConsumer - ObjDoubleConsumer ObjIntConsumer prend un objet et un int en arguments
  • 95. Function Une fonction prend un objet et retourne un autre objet public interface Function<T, R> { R apply(T t) ; } 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
  • 96. Predicate Un Predicate prend un objet et retourne un booléen public interface Predicate<T> { boolean test(T t) ; } Il peut être inversé, et composé avec des AND ou OR
  • 97. BiPredicate Un BiPredicate prend deux objets et retourne un booléen public interface BiPredicate<T, U> { boolean test(T t, U u) ; } Version pour les types booléens
  • 98. Retour sur map / filter / reduce
  • 99. La façon JDK 7 Comment implémenter le pattern map / filter / reduce sur List<Person> ?
  • 100. La façon JDK 7 Comment implémenter le pattern map / filter / reduce sur List<Person> ? La façon classique est d’itérer sur les éléments et d’appliquer le pattern
  • 101. La façon JDK 7 Comment implémenter le pattern map / filter / reduce sur List<Person> ? La façon classique est d’itérer sur les éléments et d’appliquer le pattern On peut pour cela créer une méthode helper
  • 102. 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() ) ;
  • 103. Mapping d’une liste Mapping en JDK 8 avec des lambdas List<Person> persons = new ArrayList<>() ; List<Integer> ages = Lists.map( persons, Person::getAge ) ;
  • 104. Pattern complet Le pattern va ressembler à ça : // 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) ;
  • 105. Pattern complet Le pattern va ressembler à ça : // 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) ; L’idée est de pousser un lambda vers l’implémentation, et de la laisser itérer en interne
  • 106. Pattern complet Le pattern va ressembler à ça : // 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) ; Pour : l’API peut être optimisée sans que l’on ait à toucher au code, super !
  • 107. Pattern complet Le pattern va ressembler à ça : // 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) ; Pour : l’API peut être optimisée sans que l’on ait à toucher au code, super ! Contre…
  • 108. 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) ;
  • 109. 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) ; 2 duplications : ages & agesGT20
  • 110. 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) ; 2 duplications : ages & agesGT20 Que fait-on de ces listes ? On les envoie au GC !
  • 111. Pattern complet 2) Supposons que les algorithmes de calcul du map / filter / reduce soient déjà optimisés // 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) ;
  • 112. Pattern complet 2) Supposons que les algorithmes de calcul du map / filter / reduce soient déjà optimisés // 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) ; … mais on doit encore gagner du temps !
  • 113. Pattern complet 2) Supposons que les algorithmes de calcul du map / filter / reduce soient déjà optimisés // 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) ; Seule solution : paralléliser !
  • 114. Pattern complet 2) Supposons que l’on veuille paralléliser… // 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) ; Il faut mieux que ages et agesGT20 soient des collections concurrentes !
  • 115. Pattern complet 3) Supposons que nous aillons un reducer : 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) ; allMatch est vrai si tous les noms sont plus courts que 20 caractères Voyons une implémentation possible de allMatch()
  • 116. É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 ; }
  • 117. É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 !
  • 118. É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 ; } Sauf que…
  • 119. Pattern complet Quand on applique la réduction allMatch()… // pattern map / filter / reduce List<Person> persons = ... ; List<String> names = Lists.map(persons, p -> p.getName()) ; boolean allMatch = Lists.allMatch(names, n.length() < 20) ; … names a déjà été évaluée !
  • 120. Pattern complet Quand on applique la réduction allMatch()… // pattern map / filter / reduce List<Person> persons = ... ; List<String> names = Lists.map(persons, p -> p.getName()) ; boolean allMatch = Lists.allMatch(names, n.length() < 20) ; … names a déjà été évaluée ! On a perdu une belle optimisation…
  • 121. Pattern complet Quand on applique la réduction allMatch()… // pattern map / filter / reduce List<Person> persons = ... ; List<String> names = Lists.map(persons, p -> p.getName()) ; boolean allMatch = Lists.allMatch(names, n.length() < 20) ; … names a déjà été évaluée ! Il aurait fallu appliquer le mapping de façon lazy
  • 122. Conclusion Pour : 1 Contre : 3 (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) ;
  • 123. Conclusion Pour : 1 Contre : 3 (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) ;
  • 124. 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) ;
  • 125. Conclusion (again) On a besoin d’un nouveau concept pour traiter les listes de grande taille de façon efficace
  • 126. Conclusion (again) On a besoin d’un nouveau concept pour traiter les listes de grande taille de façon efficace Le framework Collection n’apporte pas de solution satisfaisante
  • 127. Conclusion (again) On a besoin d’un nouveau concept pour traiter les listes de grande taille de façon efficace Le framework Collection n’apporte pas de solution satisfaisante On a besoin de quelque chose d’autre !
  • 129. Introduction Implémenter le map / filter / reduce sur Collection aurait mené à ceci : // map / filter / reduce pattern sur Collection int sum = persons .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ; Et même si cette approche n’est pas viable, c’est une façon agréable d’écrire les choses
  • 130. 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) ;
  • 131. Introduction Collection.stream() retourne un Stream : une nouvelle interface // 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 = on a les mains libres !
  • 132. 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() ; }
  • 133. 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() ; }
  • 134. Interfaces Problème : ArrayList ne compile plus… Une solution doit être trouvée ! Une solution qui ne nécessite pas de modifier ou de recompiler toutes les implémentations existantes de Collection !
  • 136. Interfaces Java 8 Problème : ArrayList ne compile plus… Une solution doit être trouvée ! Une solution qui ne nécessite pas de modifier ou de recompiler toutes les implémentations existantes de Collection ! Problème : ajouter des méthodes à une interface sans toucher aux implémentations…
  • 137. Interfaces Java 8 Problème : ajouter des méthodes à une interface sans toucher aux implémentations… Solution : changer la façon dont les interfaces fonctionnent en Java !
  • 138. Interfaces Java 8 ArrayList a besoin de l’implémentation de stream()… public interface Collection<E> { // nos bonnes vieilles méthodes Stream<E> stream() ; }
  • 139. Interfaces Java 8 Solution : mettons-les dans l’interface ! public interface Collection<E> { // nos bonnes vieilles méthodes default Stream<E> stream() { return ... ; } }
  • 140. Interfaces Java 8 Introduisons les default methods en Java public interface Collection<E> { // nos bonnes vieilles méthodes default Stream<E> stream() { return ... ; } } Les méthodes par défaut permettent de faire évoluer de vieilles interfaces
  • 141. Méthodes par défaut Cela amène-t-il l’héritage multiple en Java ?
  • 142. Méthodes par défaut Cela amène-t-il l’héritage multiple en Java ? Oui, mais on l’a déjà
  • 143. Méthodes par défaut Cela amène-t-il l’héritage mutliple en Java ? Oui, mais on l’a déjà public class String implements Serializable, Comparable<String>, CharSequence { // ... }
  • 144. Méthodes par défaut Ce que l’on a en Java est l’héritage multiple de type
  • 145. 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
  • 146. 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
  • 147. 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 !
  • 148. Méthodes par défaut Peut-on avoir des conflits ?
  • 149. Méthodes par défaut Peut-on avoir des conflits ? Hélas oui…
  • 150. Méthodes par défaut Peut-on avoir des conflits ? Hélas oui… Il nous faut donc des règles pour les gérer
  • 151. Méthodes par défaut public class C implements A, B { // ... }
  • 152. Méthodes par défaut public class C implements A, B { // ... } public interface A { default String a() { ... } } public interface B { default String a() { ... } }
  • 153. Méthodes par défaut public class C implements A, B { public String a() { ... } } Exemple #0 public interface A { default String a() { ... } } public interface B { default String a() { ... } } La classe gagne ! L’implémentation efface la méthode par défaut
  • 154. Méthodes par défaut public class C implements A, B { // ... } Exemple #1 public interface A { default String a() { ... } } public interface B { default String a() { ... } }
  • 155. Méthodes par défaut public class C implements A, B { // ... } Exemple #1 public interface A { default String a() { ... } } public interface B { default String a() { ... } } Erreur de compilation : class C inherits unrelated defaults for a() from types A and B
  • 156. Méthodes par défaut public class C implements A, B { // ... } Exemple #2 public interface A extends B { default String a() { ... } } public interface B { default String a() { ... } } A est plus spécifique que B : A.a() a la priorité
  • 157. Méthodes par défaut public class D extends C implements B { // ... } public class C implements A { // ... } Exemple #2 public interface A extends B { default String a() { ... } } public interface B { default String a() { ... } }
  • 158. Méthodes par défaut public class D extends C implements B { // ... } public class C implements A { // ... } Exemple #2 public interface A extends B { default String a() { ... } } public interface B { default String a() { ... } } A est toujours plus spécifique que B : A.a() gagne
  • 159. Méthodes par défaut public class C implements A, B { public String a() { return B.super.a() ; } } Retour sur l’exemple #1 public interface A { default String a() { ... } } public interface B { default String a() { ... } } On peut aussi faire un appel explicite
  • 160. 2 règles simples Pour gérer les conflits de l’héritage multiple d’implémentation
  • 161. 2 règles simples Pour gérer les conflits de l’héritage multiple d’implémentation 1) La classe gagne
  • 162. 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
  • 163. 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 !") ; } ; }
  • 164. Un exemple Grâce à Java 8 : public interface Iterator<E> { default void remove() { throw new UnsupportedOperationException("remove") ; } ; } Plus besoin d’écrire ce code !
  • 165. 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!") ; } ; }
  • 166. 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!") ; } ; }
  • 167. 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
  • 168. 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
  • 170. Qu’est-ce qu’un Stream ? D’un point de vue technique : une interface paramétrée « un stream de String »
  • 171. Qu’est-ce qu’un Stream ? D’un point de vue technique : une interface paramétrée « un stream de String » D’autres interfaces pour les types primitifs : IntStream, LongStream, DoubleStream
  • 172. Une nouvelle notion Cela ressemble à une collection, mais… - Un Stream est construit sur une « source » - Pas de donnée à la construction - Pas de limite sur ce qu’une source peut produire
  • 173. Une nouvelle notion Un Stream peut être construit sur : - Une collection ou un tableau - Un itérateur - Un source I/O Certaines de ces sources sont « infinies »
  • 174. 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
  • 175. 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
  • 176. 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
  • 177. Une nouvelle notion 1) 2) 3) 4) Un stream ne porte pas de donnée Un stream ne peut pas modifier sa source Une source peut être infinie, ou non bornée 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
  • 178. Un Stream est-il une Collection ? La réponse est non
  • 179. Un Stream est-il une Collection ? La réponse est non Une collection permet d’itérer sur ses éléments
  • 180. Un Stream est-il une Collection ? La réponse est non Une collection permet d’itérer sur ses éléments Pas un Stream
  • 181. Un Stream est-il une Collection ? La réponse est non Une collection ne permet pas d’appliquer un lambda sur ses éléments
  • 182. Un Stream est-il une Collection ? La réponse est non Une collection ne permet pas d’appliquer un lambda sur ses éléments Un Stream le peut
  • 183. Comment construire un Stream ? De nombreuses façons de faire… 1) À partir d’une collection : Collection<String> collection = ... ; Stream<String> stream = collection.stream() ;
  • 184. 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"}) ;
  • 185. 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") ;
  • 186. 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) ;
  • 187. 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
  • 188. Un premier exemple Retour sur notre map / filter / reduce Construction d’un collections Stream sur une List // map / filter / reduce pattern on int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;
  • 189. Un premier exemple Retour sur notre map / filter / reduce Déclarations // map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;
  • 190. Un premier exemple Retour sur notre map / filter / reduce On lance le collections calcul // map / filter / reduce pattern on int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;
  • 191. 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
  • 192. 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
  • 193. 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
  • 194. 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)
  • 195. Un Stream possède un état Certaines opérations changent cet état - le filtrage annule SIZED - le mapping annule DISTINCT et SORTED
  • 196. Un Stream possède un état Et cela permet d’optimiser ! - un HashSet ne peut pas avoir de doublons…
  • 197. 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
  • 198. 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…
  • 199. 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… - sort() ne fait rien pour un stream construit sur un TreeSet
  • 200. Un ème 2 exemple Trions une liste de chaîne de caractères List<String> strings = new ArrayList<>() ; // on remplit la liste // et plus loin dans le code on a ça : List<String> result = strings.stream() .sorted() .collect(Collector.toList()) ;
  • 201. Un ème 2 exemple Trions une liste de chaîne de caractères // un jour un petit malin change l’implémentation SortedSet<String> strings = new TreeSet<>() ; // on remplit la liste // et plus loin dans le code on a ça : List<String> result = strings.stream() .sorted() .collect(Collector.toList()) ;
  • 202. Un ème 2 exemple Trions une liste de chaîne de caractères // un jour un petit malin change l’implémentation SortedSet<String> strings = new TreeSet<>() ; // on remplit la liste // et plus loin dans le code on a ça : List<String> result = strings.stream() .sorted() .collect(Collector.toList()) ; Dans ce cas le code de tri n’est plus exécuté !
  • 203. Opérations stateless / statefull Opérations Stateless / statefull Certaines opérations sont stateless : persons.stream().map(p -> p.getAge()) ; Cela signifie que l’on n’a pas besoin de plus d’information que ce qui est contenu dans p
  • 204. Opérations stateless / statefull Opérations Stateless / statefull Certaines opérations sont stateless : persons.stream().map(p -> p.getAge()) ; Pas le cas de toutes les opérations stream.limit(10_000_000) ; // select les premiers 10M éléments
  • 205. 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()) ; }
  • 206. 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()) ; } Soooo Java 7…
  • 207. Exemple Trions un tableau de String Random rand = new Random() ; Stream<String> stream = Stream.generate( () -> Long.toHexString(rand.nextLong()) ) ; Meilleur ?
  • 208. Exemple Trions un tableau de String // Random rand = new Random() ; Stream<String> stream = Stream.generate( () -> Long.toHexString(ThreadLocalRandom.current().nextLong()) ) ; Meilleur !
  • 209. Exemple Trions un tableau de String // other way Stream<String> stream = ThreadLocalRandom .current() .longs() // returns a LongStream .mapToObj(l -> Long.toHexString(l)) ;
  • 210. Exemple Trions un tableau de String // other way Stream<String> stream = ThreadLocalRandom .current() .longs() .mapToObj(Long::toHexString) ;
  • 211. 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
  • 212. 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() ;
  • 213. 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
  • 214. Example Trions un tableau de String // other way Stream<String> stream = ThreadLocalRandom .current() .longs() .mapToObj(Long::toHexString) .limit(10_000_000) .sorted() ; Opérations intermédiares ! Object [] sorted = stream.toArray() ; T = 14 s
  • 215. 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
  • 216. 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
  • 218. 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
  • 219. 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
  • 220. Construction d’un Stream parallèle Deux patterns 1) Appeler parallelStream() au lieu de stream() Stream<String> s = strings.parallelStream() ; 2) Appeler parallel() sur un stream existant Stream<String> s = strings.stream().parallel() ;
  • 221. Peut-on choisir le nombre cœurs ? La réponse est non
  • 222. Peut-on choisir le nombre cœurs ? La réponse est non Mais… en a-t-on vraiment besoin ?
  • 223. Paralléliser est-il aussi simple ? En fait oui !
  • 224. Paralléliser est-il aussi simple ? En fait oui ! … et non…
  • 225. Paralléliser est-il aussi simple ? Exemple 1 : persons.stream().limit(10_000_000) ; « retourne les premiers 10M éléments »
  • 226. Paralléliser est-il aussi simple ? Exemple 1 : persons.parallelStream().limit(10_000_000) ; « retourne les premiers 10M éléments »
  • 227. Paralléliser est-il aussi simple ? Exemple 1 : persons.parallelStream().limit(10_000_000) ; « retourne les premiers 10M éléments » Comment peut-on tracer que les éléments sont les premiers sur un CPU multicœur ?
  • 228. 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()) ; }
  • 229. 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()) ;
  • 230. 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()) ;
  • 231. Paralléliser est-il aussi simple ? Exemple 1 : performances Code 1 (for) Code 2 (limit) Code 3 (longs) Série 270 ms 310 ms 250 ms Parallèle
  • 232. Paralléliser est-il aussi simple ? Exemple 1 : performances Code 1 (for) Code 2 (limit) Code 3 (longs) Série 270 ms 310 ms 250 ms Parallèle 500 ms 320 ms
  • 233. Paralléliser est-il aussi simple ? Exemple 2 : Stream s3 = Stream.concat(stream1, stream2) ; « retourne un Stream composé des éléments du premier Stream, puis des éléments du second »
  • 234. 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
  • 236. Qu’est-ce qu’une réduction ? 2 types de réduction : 1) La réduction « A reduction operation (also called a fold) takes a sequence of input elements and combines them into a single summary result by repeated application of a combining operation »
  • 237. Qu’est-ce qu’une réduction ? 2 types de réduction : 2) La réduction mutable « A mutable reduction operation accumulates input elements into a mutable result container, such as a Collection or StringBuilder, as it processes the elements in the stream »
  • 238. Une réduction simple La somme des âges // map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;
  • 239. Une réduction simple Ca serait bien de pouvoir écrire : // map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .sum() ; Mais sum() n’est pas définie sur Stream<T> Que voudrait dire « additionner des personnes » ?
  • 240. Une réduction simple Ca serait bien de pouvoir écrire : // map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .sum() ; Mais sum() n’est pas définie sur Stream<T> Mais il y a une méthode sum() sur IntStream !
  • 241. Une réduction simple 2ème version : // map / filter / reduce pattern on collections int sum = persons.stream() .map(Person::getAge) .filter(a -> a > 20) .mapToInt(Integer::intValue) .sum() ; Résultat pour une liste vide : 0
  • 242. Une réduction simple 2ème version (encore meilleure) : // map / filter / reduce pattern on collections int sum = persons.stream() .mapToInt(Person::getAge) .filter(a -> a > 20) // .mapToInt(Integer::intValue) .sum() ; Résultat pour une liste vide : 0
  • 243. Une réduction simple Qu’en est-il de min() et de max() ? // map / filter / reduce pattern on collections ....... = persons.stream() .mapToInt(Person::getAge) .filter(a -> a > 20) .max() ; Quelle valeur par défaut pour max() ?
  • 244. Problème des valeurs par défaut La notion de « valeur par défaut » est plus complexe qu’il y paraît…
  • 245. 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
  • 246. 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
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255. 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
  • 256. 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
  • 257. 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
  • 258. Problème des valeurs par défaut Donc quelle est la valeur par défaut de max() et min() ?
  • 259. 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()
  • 260. 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() ;
  • 261. 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() ; Si c’est int, la valeur par défaut sera 0…
  • 262. 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 »
  • 263. 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 » }
  • 264. 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() ;
  • 265. 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) ;
  • 266. 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) ;
  • 268. Réductions disponibles Sur Stream<T> : - reduce() - count(), min(), max() - anyMatch(), allMatch(), noneMatch() - findFirst(), findAny() - toArray() - forEach(), forEachOrdered()
  • 269. Réductions disponibles Sur IntStream, LongStream, DoubleStream : - average() - summaryStatistics()
  • 270. Mutable reductions : exemple 1 Utilisation d’une classe helper : Collectors ArrayList<String> strings = stream .map(Object::toString) .collect(Collectors.toList()) ;
  • 271. Mutable reductions : exemple 2 Concaténation de String avec un helper String names = persons .stream() .map(Person::getName) .collect(Collectors.joining()) ;
  • 272. 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)
  • 273. Mutable reductions La forme générale a donc besoin de 3 objets : - un supplier : construit une instance du container Supplier<ArrayList<String>> supplier = () -> new ArrayList<String>() ;
  • 274. Mutable reductions La forme générale a donc besoin de 3 objets : - un supplier : construit une instance du container - un accumulateur : ajoute un élément au container BiConsumer<ArrayList<String>, ? super String> accumulator = (suppliedList, s) -> suppliedList.add(s) ;
  • 275. Mutable reductions La forme générale a donc besoin de 3 objets : - un supplier : construit une instance du container - un accumulateur : ajoute un élément au container - un combiner : fusionne deux containers BiConsumer<ArrayList<String>, ArrayList<String>> combiner = (supplied1, supplied2) -> supplied1.addAll(supplied2) ;
  • 276. Mutable reductions : exemple 1 D’où le code : ArrayList<String> strings = stream .map(Object::toString) .collect( () -> new ArrayList<String>(), // the supplier (suppliedList, s) -> suppliedList.add(s), // the accumulator (supplied1, supplied2) -> supplied1.addAll(supplied2) // the combiner ) ;
  • 277. Mutable reductions : exemple 1 D’où le code : ArrayList<String> strings = stream .map(Object::toString) .collect( ArrayList::new, // the supplier ArrayList::add, // the accumulator ArrayList::addAll // the combiner ) ;
  • 279. 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 Et - mapping, groupingBy, partionningBy
  • 280. La classe Collectors Average, Sum, Count persons .stream() .collect(Collectors.averagingDouble(Person::getAge)) ; persons .stream() .collect(Collectors.counting()) ;
  • 281. La classe Collectors Concaténation des nom dans une String String names = persons .stream() .map(Person::getName) .collect(Collectors.joining(", ")) ;
  • 282. La classe Collectors Accumulation dans un Set Set<Person> setOfPersons = persons .stream() .collect( Collectors.toSet()) ;
  • 283. La classe Collectors Accumulation dans une collection passée en paramètre TreeSet<Person> treeSetOfPersons = persons .stream() .collect( Collectors.toCollection(TreeSet::new)) ;
  • 284. La classe Collectors Calculer un max avec un comparateur Optional<Person> optionalPerson = persons .stream() .collect( Collectors.maxBy( Comparator.comparing(Person::getAge)) ; Bonus : une API Comparator
  • 285. Construction de comparateurs Nouvelle API pour construire des comparateurs Comparator<Person> comp = Comparator.comparing(Person::getLastName) .thenComparing(Person::getFirstName) .thenComparing(Person:getAge) ;
  • 286. 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
  • 287. Classe Collectors : mapping Accumuler les noms des personnes dans un Set Set<String> set = persons .stream() .collect( Collectors.mapping( Person::getLastName, Collectors.toSet())) ;
  • 288. Classe Collectors : mapping Mapper le stream, accumulation dans une collection TreeSet<String> set = persons .stream() .collect( Collectors.mapping( Person::getLastName, Collectors.toCollection(TreeSet::new)) ) ;
  • 289. 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)
  • 290. Classe Collectors : groupingBy Des personnes par âge Map<Integer, List<Person>> map = persons .stream() .collect( Collectors.groupingBy(Person::getAge)) ;
  • 291. Classe Collectors : groupingBy … rangées dans des Set Map<Integer, Set<Person>> map = persons .stream() .collect( Collectors.groupingBy( Person::getAge, Collectors.toSet() // le downstream ) ;
  • 292. 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() // ) ) ;
  • 293. 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) ) ) ;
  • 294. 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) ) ) ;
  • 295. Classe Collectors : groupingBy Exemple : création d’un histogramme des âges Map<Integer, Long> map = persons .stream() .collect( Collectors.groupingBy(Person::getAge, Collectors.counting()) ) ; Donne le nombre de personnes par âge
  • 296. 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
  • 297. Classe Collectors : partionningBy Crée une Map<Boolean, …> avec un prédicat Map<Boolean, List<Person>> map = persons .stream() .collect( Collectors.partitioningBy(p -> p.getAge() > 20) ) ; map.get(TRUE) retourne la liste des personnes de plus de 20 ans
  • 298. 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)) ) ) ) ;
  • 299. Classe Collectors : collectingAndThen Collecte les données avec un downstream Applique enfin une fonction appelée « finisher » Indispensable pour retourner des collections immutables
  • 300. Classe Collectors : collectingAndThen 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 ) ; Dans ce cas « Map::entrySet » est un finisher
  • 302. er 1 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()) ;
  • 303. er 1 exemple Un stream de movies 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()) ;
  • 304. er 1 exemple Construction d’une map année / # de films 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()) ;
  • 305. er 1 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
  • 306. er 1 exemple Et déterminer la plus grande valeur 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()) ;
  • 307. er 1 exemple Retourne l’année qui a vu le plus grand nombre de films 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()) ;
  • 309. Traitement parallèle Deux façons de le faire : - créer un stream parallèle d’entrée - Appeler parallel() sur un stream donné, on peut aussi appeler sequential() Quand une opération terminale est appelée, l’ensemble des opérations est exécuté en parallèle ou pas, en fonction du mode du stream
  • 310. Les choses qui ne marchent pas Certaines opérations ne donnent pas des résultats reproductibles en parallèle, ex : findAny() On ne doit pas modifier la source durant le traitement, si on le fait les résultats ne sont pas prévisibles, même si la source est une collection concurrente
  • 311. Les choses qui marchent pas, mais… Le traitement parallèle doit être le moins contraint possible pour être efficace - ORDERED est une contrainte coûteuse - collect() doit utiliser des structures concurrentes
  • 313. Conclusion Pourquoi les lambdas ont-ils été introduits dans Java 8 ?
  • 314. Conclusion Pourquoi les lambdas ont-ils été introduits dans Java 8 ? Réponse : parce que c’est à la mode !
  • 315.
  • 316. Conclusion Pourquoi les lambdas ont-ils été introduits dans Java 8 ? Réponse : parce que c’est à la mode !
  • 317. 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 !
  • 318. 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
  • 319. 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
  • 320. 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 !
  • 321. 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
  • 322. Conclusion Java 8 arrive, il s’agit de la mise à jour la plus importante depuis 15 ans que Java existe
  • 323. 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 travail
  • 324. 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 travail - convaincre nos boss…
  • 325. 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
  • 326. 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
  • 327. 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
  • 328. 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 !