20140123 java8 lambdas_jose-paumard-soat

271
JDK 8 & Lambdas Lambdas, Streams, Collectors

Upload: soat

Post on 31-May-2015

154 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 20140123 java8 lambdas_jose-paumard-soat

JDK 8 & Lambdas

Lambdas, Streams, Collectors

Page 2: 20140123 java8 lambdas_jose-paumard-soat

Pourquoi ont-ils été introduits ?

Page 3: 20140123 java8 lambdas_jose-paumard-soat

Pourquoi ont-ils été introduits ?

Comment vont-ils changer nos habitudes de

programmation ?

Page 4: 20140123 java8 lambdas_jose-paumard-soat
Page 5: 20140123 java8 lambdas_jose-paumard-soat

Année d’édition

1994

Page 6: 20140123 java8 lambdas_jose-paumard-soat

Année d’édition

1994

En stock. Expédié et vendu par Amazon. Emballage cadeau disponible.

Page 7: 20140123 java8 lambdas_jose-paumard-soat
Page 8: 20140123 java8 lambdas_jose-paumard-soat
Page 9: 20140123 java8 lambdas_jose-paumard-soat

Formation Java 8

6 & 7 février 2014

BBL

Page 10: 20140123 java8 lambdas_jose-paumard-soat
Page 11: 20140123 java8 lambdas_jose-paumard-soat

Introduisons les lambdas

Page 12: 20140123 java8 lambdas_jose-paumard-soat

Introduisons les lambdas sur un exemple simple

Page 13: 20140123 java8 lambdas_jose-paumard-soat

Un exemple très simple

public class Person { private String name ; private int age ; // constructors // getters / setters }

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

Un bon vieux bean

… et une bonne vieille liste

Page 14: 20140123 java8 lambdas_jose-paumard-soat

int sum = 0 ; // I need a default value in case // the list is empty int average = 0 ; for (Person person : list) { sum += person.getAge() ; } if (!list.isEmpty()) { average = sum / list.size() ; }

Calculons la moyenne des âges des personnes

Page 15: 20140123 java8 lambdas_jose-paumard-soat

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

Page 16: 20140123 java8 lambdas_jose-paumard-soat

« programmation impérative »

int sum = 0 ; int n = 0 ; int average = 0 ; for (Person person : list) { if (person.getAge() > 20) { n++ ; sum += person.getAge() ; } } if (n > 0) { average = sum / n ; }

Plus dur : pour les personnes de plus de 20 ans

Page 17: 20140123 java8 lambdas_jose-paumard-soat

select avg(age) from Person where age > 20

… pas une obligation !

Ici on décrit le résultat

Page 18: 20140123 java8 lambdas_jose-paumard-soat

select avg(age) from Person where age > 20

Dans ce cas la base de données mène le calcul

comme elle l’entend

© SQL 1974

… pas une obligation !

Ici on décrit le résultat

Page 19: 20140123 java8 lambdas_jose-paumard-soat

Person age age > 20 sum

1ère étape : mapping

map

Page 20: 20140123 java8 lambdas_jose-paumard-soat

Mapping :

- prend une liste d’un type donné

- retourne une liste d’un autre type

- possède le même nombre d’éléments

1ère étape : mapping

map

Person age age > 20 sum

Page 21: 20140123 java8 lambdas_jose-paumard-soat

2ème étape : filtrage

filter map

Person age age > 20 sum

Page 22: 20140123 java8 lambdas_jose-paumard-soat

Filtrage :

- prend une liste d’un type donné

- retourne une liste du même type

- mais avec moins d’éléments

Person age age > 20 sum

2ème étape : filtrage

filter map

Page 23: 20140123 java8 lambdas_jose-paumard-soat

3ème étape : réduction

reduce filter map

Person age age > 20 sum

Page 24: 20140123 java8 lambdas_jose-paumard-soat

Reduction : agrégation des éléments d’une

liste dans un seul élément

Ex : moyenne, somme, min, max, etc…

Person age age > 20 sum

3ème étape : réduction

reduce filter map

Page 25: 20140123 java8 lambdas_jose-paumard-soat

Comment peut-on

modéliser ce traitement ?

Page 26: 20140123 java8 lambdas_jose-paumard-soat

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) ; }

Page 27: 20140123 java8 lambdas_jose-paumard-soat

Mapper<Person, Integer> mapper = new Mapper<Person, Integer>() { public Integer map(Person p) { return p.getAge() ; } }

La façon JDK 7

… et on crée une classe anonyme

public interface Mapper<T, V> { public V map(T t) ; }

Page 28: 20140123 java8 lambdas_jose-paumard-soat

AgePredicate predicate = new Predicate<Integer>() { public boolean filter(Integer i) { return i > 20 ; } }

public interface Predicate<T> { public boolean filter(T t) ; }

La façon JDK 7

On peut faire la même chose pour le filtrage

Page 29: 20140123 java8 lambdas_jose-paumard-soat

Reducer<Integer> reduction = new Reducer<Integer>() { public Integer reduce(Integer i1, Integer i2) { return i1 + i2 ; } }

public interface Reducer<T> { public T reduce(T t1, T t2) ; }

La façon JDK 7

Et enfin pour la réduction

Page 30: 20140123 java8 lambdas_jose-paumard-soat

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

Page 31: 20140123 java8 lambdas_jose-paumard-soat

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…

Page 32: 20140123 java8 lambdas_jose-paumard-soat

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…

Page 33: 20140123 java8 lambdas_jose-paumard-soat

À la façon du JDK 8

Page 34: 20140123 java8 lambdas_jose-paumard-soat

mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { return person.getAge() ; } }

La façon du JDK 8

Prenons l’exemple du Mapper

Page 35: 20140123 java8 lambdas_jose-paumard-soat

mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return person.getAge() ; } }

Prenons l’exemple du Mapper

La façon du JDK 8

Page 36: 20140123 java8 lambdas_jose-paumard-soat

mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return p.getAge() ; } }

mapper = (Person person) ;

On prend

person

La façon du JDK 8

Prenons l’exemple du Mapper

Page 37: 20140123 java8 lambdas_jose-paumard-soat

mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return person.getAge() ; } }

mapper = (Person person) -> ;

et…

La façon du JDK 8

Prenons l’exemple du Mapper

Page 38: 20140123 java8 lambdas_jose-paumard-soat

mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return person.getAge() ; } }

mapper = (Person person) -> person.getAge() ;

… on retourne son âge

La façon du JDK 8

Prenons l’exemple du Mapper

Page 39: 20140123 java8 lambdas_jose-paumard-soat

Prenons l’exemple du Mapper

Le compilateur reconnaît cette expression comme une

implémentation du mapper

mapper = new Mapper<Person, Integer>() { public Integer map(Person person) { // 1 méthode return person.getAge() ; } }

mapper = (Person person) -> person.getAge() ;

La façon du JDK 8

Page 40: 20140123 java8 lambdas_jose-paumard-soat

Que se passe-t-il si …

… il y a plus d’une ligne de code ?

Accolades, un return explicite

mapper = (Person person) -> { System.out.println("Mapping " + person) ; return person.getAge() ; }

Page 41: 20140123 java8 lambdas_jose-paumard-soat

Que se passe-t-il si …

…le type de retour est void ?

consumer = (Person person) -> p.setAge(p.getAge() + 1) ;

Page 42: 20140123 java8 lambdas_jose-paumard-soat

Que se passe-t-il si …

…la méthode prend plus d’un argument ?

Ou :

reducer = (int i1, int i2) -> { return i1 + i2 ; }

reducer = (int i1, int i2) -> i1 + i2 ;

Page 43: 20140123 java8 lambdas_jose-paumard-soat

La façon du JDK 8

Comment le compilateur reconnaît-il l’implémentation du

mapper ?

mapper = (Person person) -> person.getAge() ;

Page 44: 20140123 java8 lambdas_jose-paumard-soat

Comment le compilateur reconnaît-il l’implémentation du

mapper ?

1) Il ne faut qu’une méthode dans le mapper

2) Les types des paramètres et le type de retour doivent

être compatible

3) Les exceptions jetées doivent être compatibles

mapper = (Person person) -> person.getAge() ;

La façon du JDK 8

Page 45: 20140123 java8 lambdas_jose-paumard-soat

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

Page 46: 20140123 java8 lambdas_jose-paumard-soat

Et la plupart du temps, le compilateur reconnaît ceci :

Le type des paramètres peut être omis

mapper = person -> person.getAge() ; // mapper filter = age -> age > 20 ; // filter reducer = (i1, i2) -> i1 + i2 ; // reducer

D’autres lambdas

Page 47: 20140123 java8 lambdas_jose-paumard-soat

Une remarque sur la réduction

Comment cela fonctionne-t-il réellement ?

Page 48: 20140123 java8 lambdas_jose-paumard-soat
Page 49: 20140123 java8 lambdas_jose-paumard-soat
Page 50: 20140123 java8 lambdas_jose-paumard-soat
Page 51: 20140123 java8 lambdas_jose-paumard-soat
Page 52: 20140123 java8 lambdas_jose-paumard-soat
Page 53: 20140123 java8 lambdas_jose-paumard-soat
Page 54: 20140123 java8 lambdas_jose-paumard-soat
Page 55: 20140123 java8 lambdas_jose-paumard-soat
Page 56: 20140123 java8 lambdas_jose-paumard-soat
Page 57: 20140123 java8 lambdas_jose-paumard-soat

Réduction

2 exemples :

Attention :

le résultat est toujours reproductible en série

il ne l’est en général pas en parallèle

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

Page 58: 20140123 java8 lambdas_jose-paumard-soat

Pour le moment

Une expression lambda est une autre façon

d’écrire des instances de classes anonymes

Page 59: 20140123 java8 lambdas_jose-paumard-soat

Il y a d’autres syntaxes

On peut écrire :

Mais on peut aussi écrire :

mapper = person -> person.getAge() ;

mapper = Person::getAge ; // méthode non statique

Page 60: 20140123 java8 lambdas_jose-paumard-soat

Il y a d’autres syntaxes

On peut écrire :

Ou encore :

sum = (i1, i2) -> i1 + i2 ; sum = Integer::sum ; // méthode statique, nouvelle !

max = (i1, i2) -> i1 > i2 ? i1 : i2 ; max = Integer::max ; // méthode statique, nouvelle !

Page 61: 20140123 java8 lambdas_jose-paumard-soat

Il y a d’autres syntaxes

Encore un autre exemple :

toLower = String::toLowerCase ;

// !!!! NON NON NON !!!! toLowerFR = String::toLowerCase(Locale.FRANCE) ;

Page 62: 20140123 java8 lambdas_jose-paumard-soat

Plus loin sur les lambdas

Page 63: 20140123 java8 lambdas_jose-paumard-soat

Questions :

Comment modéliser une expression lambda ?

Page 64: 20140123 java8 lambdas_jose-paumard-soat

Questions :

Comment modéliser une expression lambda ?

Puis-je mettre une expression lambda dans une variable ?

Page 65: 20140123 java8 lambdas_jose-paumard-soat

Questions :

Comment modéliser une expression lambda ?

Puis-je mettre une expression lambda dans une variable ?

Un lambda est-il un objet ?

Page 66: 20140123 java8 lambdas_jose-paumard-soat

Modélisation

Un lambda = instance d’une « interface fonctionnelle »

@FunctionalInterface public interface Consumer<T> { public void accept(T t) ; }

Page 67: 20140123 java8 lambdas_jose-paumard-soat

Modélisation

Un lambda = instance d’une « interface fonctionnelle »

- ne possède qu’une unique méthode

@FunctionalInterface public interface Consumer<T> { public void accept(T t) ; }

Page 68: 20140123 java8 lambdas_jose-paumard-soat

Modélisation

Un lambda = instance d’une « interface fonctionnelle »

- ne possède qu’une unique méthode

- peut être annotée par @FunctionalInterface (optionnel)

@FunctionalInterface public interface Consumer<T> { public void accept(T t) ; }

Page 69: 20140123 java8 lambdas_jose-paumard-soat

Mettre un lambda dans une variable

Exemple d’un consommateur :

Consumer<String> c = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s) ; } } ;

Consumer<String> c = s -> System.out.println(s) ;

Donc :

Page 70: 20140123 java8 lambdas_jose-paumard-soat

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 ?

Page 71: 20140123 java8 lambdas_jose-paumard-soat

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) ;

Page 72: 20140123 java8 lambdas_jose-paumard-soat

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) ;

Page 73: 20140123 java8 lambdas_jose-paumard-soat

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

Page 74: 20140123 java8 lambdas_jose-paumard-soat

Des lambdas à profusion :

Java.util.functions

Page 75: 20140123 java8 lambdas_jose-paumard-soat

Java.util.functions

C’est dans ce package que sont les interfaces

fonctionnelles

Il y en a 43

Page 76: 20140123 java8 lambdas_jose-paumard-soat

Java.util.functions

Supplier

Consumer / BiConsumer

Function / BiFunction (UnaryOperator / BinaryOperator)

Predicate / BiPredicate

En plus des versions construites sur les types primitifs

Page 77: 20140123 java8 lambdas_jose-paumard-soat

Supplier

Un supplier fournit un objet

public interface Supplier<T> { T get() ; }

Page 78: 20140123 java8 lambdas_jose-paumard-soat

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) ;

Page 79: 20140123 java8 lambdas_jose-paumard-soat

Function

Une fonction prend un objet et retourne un autre objet

Les fonctions peuvent être chaînées et / ou composées

BiFunction prend deux arguments au lieu d’un

UnaryOperator et BinaryOperator opèrent sur un seul type

public interface Function<T, R> { R apply(T t) ; }

Page 80: 20140123 java8 lambdas_jose-paumard-soat

Predicate

Un Predicate prend un objet et retourne un booléen

Il peut être inversé, et composé avec des AND ou OR

public interface Predicate<T> { boolean test(T t) ; }

Page 81: 20140123 java8 lambdas_jose-paumard-soat

Retour sur

map / filter / reduce

Page 82: 20140123 java8 lambdas_jose-paumard-soat

La façon JDK 7

Comment implémenter le pattern map / filter / reduce

sur List<Person> ?

Page 83: 20140123 java8 lambdas_jose-paumard-soat

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

Page 84: 20140123 java8 lambdas_jose-paumard-soat

Mapping d’une liste

Mapping en JDK 8 avec des lambdas

List<Person> persons = new ArrayList<>() ; List<Integer> ages = Lists.map( persons, Person::getAge ) ;

Page 85: 20140123 java8 lambdas_jose-paumard-soat

Pattern complet

Le pattern va ressembler à ça :

Pour : l’API peut être optimisée sans

que l’on ait à toucher au code, super !

// pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;

Page 86: 20140123 java8 lambdas_jose-paumard-soat

Pattern complet

Le pattern va ressembler à ça :

Pour : l’API peut être optimisée sans

que l’on ait à toucher au code, super !

Contre…

// pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;

Page 87: 20140123 java8 lambdas_jose-paumard-soat

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) ;

Page 88: 20140123 java8 lambdas_jose-paumard-soat

Pattern complet

1) Supposons que persons soit vraiment GRANDE

2 duplications : ages & agesGT20

// pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;

Page 89: 20140123 java8 lambdas_jose-paumard-soat

Pattern complet

1) Supposons que persons soit vraiment GRANDE

2 duplications : ages & agesGT20

Que fait-on de ces listes ? On les envoie au GC !

// pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;

Page 90: 20140123 java8 lambdas_jose-paumard-soat

Pattern complet

2) Supposons que nous aillons un reducer : allMatch

allMatch est vrai si tous les noms sont plus courts que 20

caractères

Voyons une implémentation possible de allMatch()

// pattern map / filter / reduce List<Person> persons = ... ; List<String> names = Lists.map(persons, p -> p.getName()) ; boolean allMatch = Lists.allMatch(names, n -> n.length() < 20) ;

Page 91: 20140123 java8 lambdas_jose-paumard-soat

É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 !

Page 92: 20140123 java8 lambdas_jose-paumard-soat

Pattern complet

Quand on applique la réduction allMatch()…

… names a déjà été évaluée !

// pattern map / filter / reduce List<Person> persons = ... ; List<String> names = Lists.map(persons, p -> p.getName()) ; boolean allMatch = Lists.allMatch(names, n.length() < 20) ;

Page 93: 20140123 java8 lambdas_jose-paumard-soat

Pattern complet

Quand on applique la réduction allMatch()…

… names a déjà été évaluée !

Il aurait fallu appliquer le mapping de façon lazy

// pattern map / filter / reduce List<Person> persons = ... ; List<String> names = Lists.map(persons, p -> p.getName()) ; boolean allMatch = Lists.allMatch(names, n.length() < 20) ;

Page 94: 20140123 java8 lambdas_jose-paumard-soat

Conclusion

Pour : 1

Contre : 2 (au moins)

// pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;

Page 95: 20140123 java8 lambdas_jose-paumard-soat

// pattern map / filter / reduce List<Person> persons = ... ; List<Integer> ages = Lists.map( persons, p -> p.getAge()) ; List<Integer> agesGT20 = Lists.filter(ages, a -> a > 20) ; int sum = Lists.reduce(agesGT20, (i1, i2) -> i1 + i2) ;

Conclusion

Pour : 1

Contre : 2 (au moins)

Page 96: 20140123 java8 lambdas_jose-paumard-soat

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) ;

Page 97: 20140123 java8 lambdas_jose-paumard-soat

Conclusion (again)

On a besoin d’un nouveau concept pour traiter les listes de

grande taille de façon efficace

Page 98: 20140123 java8 lambdas_jose-paumard-soat

Quel pattern choisir ?

Page 99: 20140123 java8 lambdas_jose-paumard-soat

Introduction

Implémenter le map / filter / reduce sur Collection aurait

mené à ceci :

Et même si cette approche n’est pas viable, c’est une

façon agréable d’écrire les choses

// map / filter / reduce pattern sur Collection int sum = persons .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;

Page 100: 20140123 java8 lambdas_jose-paumard-soat

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) ;

Page 101: 20140123 java8 lambdas_jose-paumard-soat

Introduction

Collection.stream() retourne un Stream : une nouvelle

interface

Nouvelle interface = on a les mains libres !

// map / filter / reduce pattern sur Collection int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;

Page 102: 20140123 java8 lambdas_jose-paumard-soat

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() ; }

Page 103: 20140123 java8 lambdas_jose-paumard-soat

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() ; }

Page 104: 20140123 java8 lambdas_jose-paumard-soat

Nouvelles interfaces

Page 105: 20140123 java8 lambdas_jose-paumard-soat

Interfaces Java 8

Problème : ajouter des méthodes à une interface sans

toucher aux implémentations…

Page 106: 20140123 java8 lambdas_jose-paumard-soat

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

Page 107: 20140123 java8 lambdas_jose-paumard-soat

Interfaces Java 8

ArrayList a besoin de l’implémentation de stream()…

public interface Collection<E> { // nos bonnes vieilles méthodes Stream<E> stream() ; }

Page 108: 20140123 java8 lambdas_jose-paumard-soat

Interfaces Java 8

Solution : mettons-les dans l’interface !

public interface Collection<E> { // nos bonnes vieilles méthodes default Stream<E> stream() { return ... ; } }

Page 109: 20140123 java8 lambdas_jose-paumard-soat

Interfaces Java 8

Une interface devient-elle une classe abstraite ?

Page 110: 20140123 java8 lambdas_jose-paumard-soat

Interfaces Java 8

Une interface devient-elle une classe abstraite ?

Non !

- une classe abstraite peut avoir des champs et possède

un constructeur

- un appel de méthode d’une classe abstraite (ou pas) est

résolu à l’exécution

- une implémentation par défaut est juste du code, lié à la

compilation

Page 111: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

Cela amène-t-il l’héritage multiple en Java ?

Page 112: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

Cela amène-t-il l’héritage multiple en Java ?

Oui, mais on l’a déjà

Page 113: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

Cela amène-t-il l’héritage multiple en Java ?

Oui, mais on l’a déjà

public class String implements Serializable, Comparable<String>, CharSequence { // ... }

Page 114: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

Ce que l’on a en Java est l’héritage multiple de type

Page 115: 20140123 java8 lambdas_jose-paumard-soat

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

Page 116: 20140123 java8 lambdas_jose-paumard-soat

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

Page 117: 20140123 java8 lambdas_jose-paumard-soat

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 !

Page 118: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

Peut-on avoir des conflits ?

Page 119: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

Peut-on avoir des conflits ?

Hélas oui…

Page 120: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

Peut-on avoir des conflits ?

Hélas oui…

Il nous faut donc des règles pour les gérer

Page 121: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

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

Page 122: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

Exemple #1

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

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

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

Page 123: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

Exemple #1

Erreur de compilation :

class C inherits unrelated defaults for a() from types A and B

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

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

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

Page 124: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

Exemple #2

La classe gagne !

public class C implements A, B { public String a() { ... } }

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

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

Page 125: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

Exemple #3

Le plus spécifique gagne !

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

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

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

Page 126: 20140123 java8 lambdas_jose-paumard-soat

Méthodes par défaut

Retour sur l’exemple #1

On peut aussi faire un appel explicite

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

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

public class C implements A, B { public String a() { return B.super.a() ; } }

Page 127: 20140123 java8 lambdas_jose-paumard-soat

2 règles simples

Pour gérer les conflits de l’héritage multiple d’implémentation

Page 128: 20140123 java8 lambdas_jose-paumard-soat

2 règles simples

Pour gérer les conflits de l’héritage multiple d’implémentation

1) La classe gagne

Page 129: 20140123 java8 lambdas_jose-paumard-soat

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

Page 130: 20140123 java8 lambdas_jose-paumard-soat

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 !") ; } ; }

Page 131: 20140123 java8 lambdas_jose-paumard-soat

Un exemple

Grâce à Java 8 :

Plus besoin d’écrire ce code !

public interface Iterator<E> { default void remove() { throw new UnsupportedOperationException("remove") ; } ; }

Page 132: 20140123 java8 lambdas_jose-paumard-soat

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!") ; } ; }

Page 133: 20140123 java8 lambdas_jose-paumard-soat

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!") ; } ; }

Page 134: 20140123 java8 lambdas_jose-paumard-soat

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

Page 135: 20140123 java8 lambdas_jose-paumard-soat

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

Page 136: 20140123 java8 lambdas_jose-paumard-soat

L’API Stream

Page 137: 20140123 java8 lambdas_jose-paumard-soat

Qu’est-ce qu’un Stream ?

D’un point de vue technique : une interface paramétrée

« un stream de String »

Page 138: 20140123 java8 lambdas_jose-paumard-soat

Qu’est-ce qu’un Stream ?

D’un point de vue technique : une interface paramétrée

D’autres interfaces pour les types primitifs :

« un stream de String »

IntStream, LongStream, DoubleStream

Page 139: 20140123 java8 lambdas_jose-paumard-soat

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

Page 140: 20140123 java8 lambdas_jose-paumard-soat

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

Page 141: 20140123 java8 lambdas_jose-paumard-soat

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

Page 142: 20140123 java8 lambdas_jose-paumard-soat

Une nouvelle notion

1) Un stream ne porte pas de donnée

2) Un stream ne peut pas modifier sa source

3) Une source peut être infinie, ou non bornée

4) Un Stream traite ses données de façon lazy

On peut optimiser les opérations entre elles

On a besoin d’un mécanisme pour déclencher les

traitements

Page 143: 20140123 java8 lambdas_jose-paumard-soat

Comment construire un Stream ?

De nombreuses façons de faire…

1) À partir d’une collection :

Collection<String> collection = ... ; Stream<String> stream = collection.stream() ;

Page 144: 20140123 java8 lambdas_jose-paumard-soat

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"}) ;

Page 145: 20140123 java8 lambdas_jose-paumard-soat

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") ;

Page 146: 20140123 java8 lambdas_jose-paumard-soat

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) ;

Page 147: 20140123 java8 lambdas_jose-paumard-soat

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

Page 148: 20140123 java8 lambdas_jose-paumard-soat

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

Page 149: 20140123 java8 lambdas_jose-paumard-soat

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

Page 150: 20140123 java8 lambdas_jose-paumard-soat

Un premier exemple

Retour sur notre map / filter / reduce

// map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;

Construction d’un

Stream sur une List

Page 151: 20140123 java8 lambdas_jose-paumard-soat

Un premier exemple

Retour sur notre map / filter / reduce

// map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;

Déclarations

Page 152: 20140123 java8 lambdas_jose-paumard-soat

Un premier exemple

Retour sur notre map / filter / reduce

// map / filter / reduce pattern on collections int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;

On lance le

calcul

Page 153: 20140123 java8 lambdas_jose-paumard-soat

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

Page 154: 20140123 java8 lambdas_jose-paumard-soat

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)

Page 155: 20140123 java8 lambdas_jose-paumard-soat

Un Stream possède un état

Certaines opérations changent cet état

- le filtrage annule SIZED

- le mapping annule DISTINCT et SORTED

Page 156: 20140123 java8 lambdas_jose-paumard-soat

Un Stream possède un état

Et cela permet d’optimiser !

- un HashSet ne peut pas avoir de doublons…

Page 157: 20140123 java8 lambdas_jose-paumard-soat

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

Page 158: 20140123 java8 lambdas_jose-paumard-soat

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…

Page 159: 20140123 java8 lambdas_jose-paumard-soat

Un Stream possède un état

Et cela permet d’optimiser !

- un HashSet ne peut pas avoir de doublons…

- donc distinct() ne fait rien (NOP) pour un stream

construit sur un HashSet

- un TreeSet est trié, donc…

- sorted() ne fait rien pour un stream construit sur un

TreeSet

Page 160: 20140123 java8 lambdas_jose-paumard-soat

Opérations stateless / statefull

Opérations Stateless / statefull

Certaines opérations sont stateless :

Cela signifie que l’on n’a pas besoin de plus d’information

que ce qui est contenu dans p

persons.stream().map(p -> p.getAge()) ;

Page 161: 20140123 java8 lambdas_jose-paumard-soat

Opérations stateless / statefull

Opérations Stateless / statefull

Certaines opérations sont stateless :

Pas le cas de toutes les opérations

persons.stream().map(p -> p.getAge()) ;

stream.limit(10_000_000) ; // sélection des premiers 10M éléments

Page 162: 20140123 java8 lambdas_jose-paumard-soat

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()) ; }

Page 163: 20140123 java8 lambdas_jose-paumard-soat

Exemple

Trions un tableau de String

Soooo Java 7…

Random rand = new Random() ; String [] strings = new String[10_000_000] ; for (int i = 0 ; i < strings.length ; i++) { strings[i] = Long.toHexString(rand.nextLong()) ; }

Page 164: 20140123 java8 lambdas_jose-paumard-soat

Exemple

Trions un tableau de String

Meilleur ?

Random rand = new Random() ; Stream<String> stream = Stream.generate( () -> Long.toHexString(rand.nextLong()) ) ;

Page 165: 20140123 java8 lambdas_jose-paumard-soat

Exemple

Trions un tableau de String

Meilleur !

// Random rand = new Random() ; Stream<String> stream = Stream.generate( () -> Long.toHexString(ThreadLocalRandom.current().nextLong()) ) ;

Page 166: 20140123 java8 lambdas_jose-paumard-soat

Exemple

Trions un tableau de String

// other way Stream<String> stream = ThreadLocalRandom .current() .longs() // returns a LongStream .mapToObj(l -> Long.toHexString(l)) ;

Page 167: 20140123 java8 lambdas_jose-paumard-soat

Exemple

Trions un tableau de String

// other way Stream<String> stream = ThreadLocalRandom .current() .longs() .mapToObj(Long::toHexString) ;

Page 168: 20140123 java8 lambdas_jose-paumard-soat

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

Page 169: 20140123 java8 lambdas_jose-paumard-soat

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

Page 170: 20140123 java8 lambdas_jose-paumard-soat

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

Page 171: 20140123 java8 lambdas_jose-paumard-soat

Exemple

Trions un tableau de String

// other way Stream<String> stream = ThreadLocalRandom .current() .longs() .mapToObj(Long::toHexString) .limit(10_000_000) .sorted() ; Object [] sorted = stream.toArray() ;

T = 14 s

Opérations

intermédiaires !

Page 172: 20140123 java8 lambdas_jose-paumard-soat

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

Page 173: 20140123 java8 lambdas_jose-paumard-soat

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

Page 174: 20140123 java8 lambdas_jose-paumard-soat

Parallel Streams

Page 175: 20140123 java8 lambdas_jose-paumard-soat

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

Page 176: 20140123 java8 lambdas_jose-paumard-soat

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

Page 177: 20140123 java8 lambdas_jose-paumard-soat

Construction d’un Stream parallèle

Deux patterns

1) Appeler parallelStream() au lieu de stream()

2) Appeler parallel() sur un stream existant

Stream<String> s = strings.parallelStream() ;

Stream<String> s = strings.stream().parallel() ;

Page 178: 20140123 java8 lambdas_jose-paumard-soat

Paralléliser est-il aussi simple ?

En fait oui !

Page 179: 20140123 java8 lambdas_jose-paumard-soat

Paralléliser est-il aussi simple ?

En fait oui !

… et non…

Page 180: 20140123 java8 lambdas_jose-paumard-soat

Paralléliser est-il aussi simple ?

Exemple 1 :

« retourne les premiers 10M éléments »

persons.stream().limit(10_000_000) ;

Page 181: 20140123 java8 lambdas_jose-paumard-soat

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()) ; }

Page 182: 20140123 java8 lambdas_jose-paumard-soat

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

Page 183: 20140123 java8 lambdas_jose-paumard-soat

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

Page 184: 20140123 java8 lambdas_jose-paumard-soat

Paralléliser est-il aussi simple ?

Exemple 1 : performances

Série Parallèle

Code 1 (for) 270 ms

Code 2 (limit) 310 ms

Code 3 (longs) 250 ms

Page 185: 20140123 java8 lambdas_jose-paumard-soat

Paralléliser est-il aussi simple ?

Exemple 1 : performances

Série Parallèle

Code 1 (for) 270 ms

Code 2 (limit) 310 ms 500 ms

Code 3 (longs) 250 ms 320 ms

Page 186: 20140123 java8 lambdas_jose-paumard-soat

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

Page 187: 20140123 java8 lambdas_jose-paumard-soat

Réductions

Page 188: 20140123 java8 lambdas_jose-paumard-soat

La réduction simple

La somme des âges

// map / filter / reduce int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .reduce(0, (a1, a2) -> a1 + a2) ;

Page 189: 20140123 java8 lambdas_jose-paumard-soat

La réduction simple

Ca serait bien de pouvoir écrire :

Mais sum() n’est pas définie sur Stream<T>

Que voudrait dire « additionner des personnes » ?

// map / filter / reduce int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .sum() ;

Page 190: 20140123 java8 lambdas_jose-paumard-soat

La réduction simple

Ca serait bien de pouvoir écrire :

Mais sum() n’est pas définie sur Stream<T>

Mais il y a une méthode sum() sur IntStream !

// map / filter / reduce int sum = persons.stream() .map(p -> p.getAge()) .filter(a -> a > 20) .sum() ;

Page 191: 20140123 java8 lambdas_jose-paumard-soat

La réduction simple

2ème version :

Résultat pour une liste vide : 0

// map / filter / reduce int sum = persons.stream() .map(Person::getAge) .filter(a -> a > 20) .mapToInt(Integer::intValue) .sum() ;

Page 192: 20140123 java8 lambdas_jose-paumard-soat

La réduction simple

2ème version (encore meilleure) :

Résultat pour une liste vide : 0

// map / filter / reduce int sum = persons.stream() .mapToInt(Person::getAge) .filter(a -> a > 20) // .mapToInt(Integer::intValue) .sum() ;

Page 193: 20140123 java8 lambdas_jose-paumard-soat

La réduction simple

Qu’en est-il de min() et de max() ?

Quelle valeur par défaut pour max() ?

// map / filter / reduce ....... = persons.stream() .mapToInt(Person::getAge) .filter(a -> a > 20) .max() ;

Page 194: 20140123 java8 lambdas_jose-paumard-soat

Problème des valeurs par défaut

La notion de « valeur par défaut » est plus complexe qu’il y

paraît…

Page 195: 20140123 java8 lambdas_jose-paumard-soat

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

Page 196: 20140123 java8 lambdas_jose-paumard-soat

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

Page 197: 20140123 java8 lambdas_jose-paumard-soat
Page 198: 20140123 java8 lambdas_jose-paumard-soat
Page 199: 20140123 java8 lambdas_jose-paumard-soat
Page 200: 20140123 java8 lambdas_jose-paumard-soat
Page 201: 20140123 java8 lambdas_jose-paumard-soat
Page 202: 20140123 java8 lambdas_jose-paumard-soat
Page 203: 20140123 java8 lambdas_jose-paumard-soat
Page 204: 20140123 java8 lambdas_jose-paumard-soat
Page 205: 20140123 java8 lambdas_jose-paumard-soat

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

Page 206: 20140123 java8 lambdas_jose-paumard-soat

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

Page 207: 20140123 java8 lambdas_jose-paumard-soat

Problème des valeurs par défaut

Donc quelle est la valeur par défaut de max() et min() ?

Page 208: 20140123 java8 lambdas_jose-paumard-soat

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()

Page 209: 20140123 java8 lambdas_jose-paumard-soat

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

Page 210: 20140123 java8 lambdas_jose-paumard-soat

Problème des valeurs par défaut

Donc quel type choisir pour la méthode max() ?

Si c’est int, la valeur par défaut sera 0…

// map / filter / reduce pattern on collections ....... = persons.stream() .mapToInt(Person::getAge) .filter(a -> a > 20) .max() ;

Page 211: 20140123 java8 lambdas_jose-paumard-soat

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 »

Page 212: 20140123 java8 lambdas_jose-paumard-soat

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 » }

Page 213: 20140123 java8 lambdas_jose-paumard-soat

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

Page 214: 20140123 java8 lambdas_jose-paumard-soat

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) ;

Page 215: 20140123 java8 lambdas_jose-paumard-soat

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) ;

Page 216: 20140123 java8 lambdas_jose-paumard-soat

Available Optionals

Optional<T>

OptionalInt, OptionalLong, OptionalDouble

Page 217: 20140123 java8 lambdas_jose-paumard-soat

Réductions disponibles

Sur Stream<T> :

- reduce()

- count(), min(), max()

- anyMatch(), allMatch(), noneMatch()

- findFirst(), findAny()

- toArray()

- forEach(), forEachOrdered()

Page 218: 20140123 java8 lambdas_jose-paumard-soat

Réductions disponibles

Sur IntStream, LongStream, DoubleStream :

- average()

- sum()

- summaryStatistics()

Page 219: 20140123 java8 lambdas_jose-paumard-soat

Mutable reductions

Page 220: 20140123 java8 lambdas_jose-paumard-soat

Mutable reductions : exemple 1

Utilisation d’une classe helper : Collectors

ArrayList<String> strings = stream .map(Object::toString) .collect(Collectors.toList()) ;

Page 221: 20140123 java8 lambdas_jose-paumard-soat

Mutable reductions : exemple 2

Concaténation de String avec un helper

String names = persons .stream() .map(Person::getName) .collect(Collectors.joining()) ;

Page 222: 20140123 java8 lambdas_jose-paumard-soat

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)

Page 223: 20140123 java8 lambdas_jose-paumard-soat

Collectors

Page 224: 20140123 java8 lambdas_jose-paumard-soat

La classe Collectors

Une boite à outils (37 méthodes) pour la plupart des types

de réduction

- counting, minBy, maxBy

- summing, averaging, summarizing

- joining

- toList, toSet, toMap

Et

- mapping, groupingBy, partionningBy

Page 225: 20140123 java8 lambdas_jose-paumard-soat

La classe Collectors

Average, Sum, Count

persons .stream() .collect(Collectors.averagingDouble(Person::getAge)) ;

persons .stream() .collect(Collectors.counting()) ;

Page 226: 20140123 java8 lambdas_jose-paumard-soat

La classe Collectors

Concaténation des noms dans une String

String names = persons .stream() .map(Person::getName) .collect(Collectors.joining(", ")) ;

Page 227: 20140123 java8 lambdas_jose-paumard-soat

La classe Collectors

Accumulation dans un Set

Set<Person> setOfPersons = persons .stream() .collect( Collectors.toSet()) ;

Page 228: 20140123 java8 lambdas_jose-paumard-soat

La classe Collectors

Accumulation dans une collection passée en paramètre

TreeSet<Person> treeSetOfPersons = persons .stream() .collect( Collectors.toCollection(TreeSet::new)) ;

Page 229: 20140123 java8 lambdas_jose-paumard-soat

La classe Collectors

Calculer un max avec un comparateur

Bonus : une API Comparator

Optional<Person> optionalPerson = persons .stream() .collect( Collectors.maxBy( Comparator.comparing(Person::getAge)) ;

Page 230: 20140123 java8 lambdas_jose-paumard-soat

Construction de comparateurs

Nouvelle API pour construire des comparateurs

Comparator<Person> comp = Comparator.comparing(Person::getLastName) .thenComparing(Person::getFirstName) .thenComparing(Person::getAge) ;

Page 231: 20140123 java8 lambdas_jose-paumard-soat

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

Page 232: 20140123 java8 lambdas_jose-paumard-soat

Classe Collectors : mapping

Accumuler les noms des personnes dans un Set

Set<String> set = persons .stream() .collect( Collectors.mapping( Person::getLastName, Collectors.toSet())) ;

Page 233: 20140123 java8 lambdas_jose-paumard-soat

Classe Collectors : mapping

Mapper le stream, accumulation dans une collection

TreeSet<String> set = persons .stream() .collect( Collectors.mapping( Person::getLastName, Collectors.toCollection(TreeSet::new)) ) ;

Page 234: 20140123 java8 lambdas_jose-paumard-soat

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)

Page 235: 20140123 java8 lambdas_jose-paumard-soat

Classe Collectors : groupingBy

Des personnes par âge

Map<Integer, List<Person>> map = persons .stream() .collect( Collectors.groupingBy( Person::getAge)) ;

Page 236: 20140123 java8 lambdas_jose-paumard-soat

Classe Collectors : groupingBy

… rangées dans des Set

Map<Integer, Set<Person>> map = persons .stream() .collect( Collectors.groupingBy( Person::getAge, Collectors.toSet() // le downstream ) ;

Page 237: 20140123 java8 lambdas_jose-paumard-soat

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() // ) ) ;

Page 238: 20140123 java8 lambdas_jose-paumard-soat

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) ) ) ;

Page 239: 20140123 java8 lambdas_jose-paumard-soat

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) ) ) ;

Page 240: 20140123 java8 lambdas_jose-paumard-soat

Classe Collectors : groupingBy

Exemple : création d’un histogramme des âges

Donne le nombre de personnes par âge

Map<Integer, Long> map = persons .stream() .collect( Collectors.groupingBy( Person::getAge, Collectors.counting() ) ) ;

Page 241: 20140123 java8 lambdas_jose-paumard-soat

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

Page 242: 20140123 java8 lambdas_jose-paumard-soat

Classe Collectors : partionningBy

Crée une Map<Boolean, …> avec un prédicat

map.get(TRUE) retourne la liste des personnes de plus de

20 ans

Map<Boolean, List<Person>> map = persons .stream() .collect( Collectors.partitioningBy(p -> p.getAge() > 20) ) ;

Page 243: 20140123 java8 lambdas_jose-paumard-soat

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)) ) ) ) ;

Page 244: 20140123 java8 lambdas_jose-paumard-soat

Classe Collectors : collectingAndThen

Collecte les données avec un downstream

Applique enfin une fonction appelée « finisher »

Indispensable pour retourner des collections immutables

Page 245: 20140123 java8 lambdas_jose-paumard-soat

Classe Collectors : collectingAndThen

Dans ce cas « Map::entrySet » est un finisher

Set<Map.Entry<Integer, List<Person>>> set = persons .stream() .collect( Collectors.collectingAndThen( Collectors.groupingBy( Person::getAge), // downstream, construit une map Map::entrySet // finisher, appliqué à la map ) ;

Page 246: 20140123 java8 lambdas_jose-paumard-soat

Quelques exemples réels

Page 247: 20140123 java8 lambdas_jose-paumard-soat

1er exemple

Optional<Entry<Integer, Long>> opt = movies.stream().parallel() .collect( Collectors.collectingAndThen( Collectors.groupingBy( movie -> movie.releaseYear(), Collectors.counting() ), Map::entrySet ) ) .stream() .max(Map.Entry.comparingByValue()) ;

Page 248: 20140123 java8 lambdas_jose-paumard-soat

1er exemple

Optional<Entry<Integer, Long>> opt = movies.stream().parallel() .collect( Collectors.collectingAndThen( Collectors.groupingBy( movie -> movie.releaseYear(), Collectors.counting() ), Map::entrySet ) ) .stream() .max(Map.Entry.comparingByValue()) ;

Un stream de movies

Page 249: 20140123 java8 lambdas_jose-paumard-soat

1er exemple

Optional<Entry<Integer, Long>> opt = movies.stream().parallel() .collect( Collectors.collectingAndThen( Collectors.groupingBy( movie -> movie.releaseYear(), Collectors.counting() ), Map::entrySet ) ) .stream() .max(Map.Entry.comparingByValue()) ;

Construction d’une map

année / # de films

Page 250: 20140123 java8 lambdas_jose-paumard-soat

1er exemple

Optional<Entry<Integer, Long>> opt = movies.stream().parallel() .collect( Collectors.collectingAndThen( Collectors.groupingBy( movie -> movie.releaseYear(), Collectors.counting() ), Map::entrySet ) ) .stream() .max(Map.Entry.comparingByValue()) ;

Construction de

l’EntrySet

Page 251: 20140123 java8 lambdas_jose-paumard-soat

1er exemple

Optional<Entry<Integer, Long>> opt = movies.stream().parallel() .collect( Collectors.collectingAndThen( Collectors.groupingBy( movie -> movie.releaseYear(), Collectors.counting() ), Map::entrySet ) ) .stream() .max(Map.Entry.comparingByValue()) ;

Et déterminer la plus

grande valeur

Page 252: 20140123 java8 lambdas_jose-paumard-soat

1er exemple

Optional<Entry<Integer, Long>> opt = movies.stream().parallel() .collect( Collectors.collectingAndThen( Collectors.groupingBy( movie -> movie.releaseYear(), Collectors.counting() ), Map::entrySet ) ) .stream() .max(Map.Entry.comparingByValue()) ;

Retourne l’année qui a

vu le plus grand

nombre de films

Page 253: 20140123 java8 lambdas_jose-paumard-soat

Conclusion

Page 254: 20140123 java8 lambdas_jose-paumard-soat

Conclusion

Pourquoi les lambdas ont-ils été introduits dans Java 8 ?

Page 255: 20140123 java8 lambdas_jose-paumard-soat

Conclusion

Pourquoi les lambdas ont-ils été introduits dans Java 8 ?

Réponse : parce que c’est à la mode !

Page 256: 20140123 java8 lambdas_jose-paumard-soat
Page 257: 20140123 java8 lambdas_jose-paumard-soat

Conclusion

Pourquoi les lambdas ont-ils été introduits dans Java 8 ?

Réponse : parce que c’est à la mode !

Page 258: 20140123 java8 lambdas_jose-paumard-soat

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 !

Page 259: 20140123 java8 lambdas_jose-paumard-soat

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

Page 260: 20140123 java8 lambdas_jose-paumard-soat

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 !

Page 261: 20140123 java8 lambdas_jose-paumard-soat

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 !

Page 262: 20140123 java8 lambdas_jose-paumard-soat

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

Page 263: 20140123 java8 lambdas_jose-paumard-soat

Conclusion

Java 8 arrive, il s’agit de la mise à jour la plus importante

depuis 15 ans que Java existe

Page 264: 20140123 java8 lambdas_jose-paumard-soat

Conclusion

Java 8 arrive, il s’agit de la mise à jour la plus importante

depuis 15 ans que Java existe

Migrer vers Java 8 va nécessiter du travail pour nous les

développeurs

- auto-formation

- changement de nos habitudes de programmer

Page 265: 20140123 java8 lambdas_jose-paumard-soat

Conclusion

Java 8 arrive, il s’agit de la mise à jour la plus importante

depuis 15 ans que Java existe

Migrer vers Java 8 va nécessiter du travail pour nous les

développeurs

- auto-formation

- changement de nos habitudes de programmer

- convaincre nos boss…

Page 266: 20140123 java8 lambdas_jose-paumard-soat

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

Page 267: 20140123 java8 lambdas_jose-paumard-soat

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

Page 268: 20140123 java8 lambdas_jose-paumard-soat

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

Page 269: 20140123 java8 lambdas_jose-paumard-soat

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 !

Page 270: 20140123 java8 lambdas_jose-paumard-soat
Page 271: 20140123 java8 lambdas_jose-paumard-soat