• Aucun résultat trouvé

CSC4102 : Programmation orient´e objet en JAVA — Lambda expressions, Streams, Optional

N/A
N/A
Protected

Academic year: 2022

Partager "CSC4102 : Programmation orient´e objet en JAVA — Lambda expressions, Streams, Optional"

Copied!
38
0
0

Texte intégral

(1)

CSC4102 : Programmation orient´e objet en

JAVA — Lambda expressions, Streams, Optional

Denis Conan

Janvier 2022

(2)

Sommaire

1. Motivations et objectifs 2. Lambda expressions JAVA 3. Utilisation dans les tests JUnit

4. Utilisation dans la manipulation des collections : les Streams 5. Utilisation dans la gestion des r´ ef´ erences null : Optional 6. Streams + Optional

7. Mise en pratique en TP (2h) + HP (3h)

2/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(3)

1 Motivations et objectifs

1.1 Qui demande de la programmation fonctionnelle ? 1.2 Pourquoi des fonctions ?

1.3 Quels sont les objectifs de la s´ eance ?

3/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(4)

1.1 Qui demande de la programmation fonction- nelle ?

Brian Goetz, Java Language Architect, Oracle

Specification lead for JSR-335 (Lambda Expressions for the Java Programming Language) Foreword of [Naftalin, 2015]

■ H´ eritage et type param´ etr´ e = abstractions pour les donn´ ees et les m´ ethodes

Lambda expression = abstraction pour les fonctions

• 2014 : ajout des lambda expressions dans la version 8 de JAVA

• 2009 : lancement du projet Lambda

• 2006 : propositions pour ajouter le concept de « clˆ oture »/« fermeture » (closure)

• 1997 : ajout du concept de « classe anonyme » (anonymous inner class)

• 1941 : travaux d’Alonzo Church sur la th´ eorie du calcul, d’o` u vient la terminologie

■ Ce sont les premiers pas vers la programmation orient´ ee fonction, appel´ ee aussi programmation fonctionnelle

4/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(5)

1.2 Pourquoi des fonctions ?

Exemple 1 : pour programmer des r´ eactions

`

a des ´ ev´ enements d’IHM

Exemple 2 : pour parall` eliser des actions sur des grandes collections de donn´ ees

5/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

myComboBox.setOnAction((event)->{...traitements });

double maxDistance = pointList.parallelStream()

.map(p->p.distance(0, 0)) .reduce(Double::max) .orElse(0.0);

fork

fork fork

map map map map

join

reduce reduce

join join

reduce

fonctions

(6)

1.3 Quels sont les objectifs de la s´ eance ?

■ Concept de lambda expression en JAVA

■ (Utilisation dans les tests JUnit)

■ Utilisation dans la manipulation des collections avec les Streams JAVA

■ Utilisation dans la gestion des r´ ef´ erences null : Optional

■ Mais nous n’´ etudions pas la programmation orient´ ee fonction ` a proprement parler dans CSC4102

Pour d´ ecouvrir ce sujet, p.ex. :

P.-Y. Saumont, Functional Programming in Java—How functional techniques improve your Java programs,

[Saumont, 2017]

6/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(7)

2 Lambda expressions JAVA

2.1 Pr´ eliminaire : interface fonctionnelle 2.2 D´ efinition et syntaxe

2.3 Exemples de lambda expressions

2.4 Contexte d’ex´ ecution d’une lambda expression 2.5 R´ ef´ erence de m´ ethode*

2.6 Interfaces fonctionnelles standard*

. Les ´ el´ ements de cette section sont extraits des r´ ef´ erences

[Naftalin, M., 2012]

,

[Naftalin, 2015]

, et

[Bloch, 2018]

7/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(8)

2.1 Pr´ eliminaire : interface fonctionnelle

■ Une interface fonctionnelle

• Est une interface

Poss` ede une seule m´ ethode abstraite

Est annot´ ee @FunctionalInterface

■ Un exemple : public interface Consumer<T>

{

void accept(T t);

}

■ Objectif : simplifier le code avec du sucre syntaxique

De

pointList.forEach(

new Consumer<Point>(){public void accept(Point p){p.translate(1,1);}}

• ); A `

pointList.forEach(p -> p.translate(1, 1));

8/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(9)

2.2 D´ efinition et syntaxe

Lambda expression = conceptuellement une fonction

• Arguments en entr´ ee et valeur de retour

■ Syntaxe

Soit : (parameters) -> expression

Soit : (parameters) -> { statements; }

■ C’est un objet = une instance d’une interface (fonctionnelle

1

)

Runnable r = () ->{}; // cr´ee unelambda expression

// et affecte une r´ef´erence vers cette lambda expression `a r Object o = r; // transtypage vers le haut, comme pour une r´ef´erence/un objet

■ Une lambda peut ˆ etre utilis´ ee l` a o` u une interface fonctionnelle est d´ eclar´ ee

• Interface fonctionnelle = ⇒ une m´ ethode = ⇒ pas d’ambigu¨ıt´ e

P.ex., « public void forEach(Consumer<? super T> consumer); » permet d’´ ecrire « pointList.forEach(p -> p.translate(1, 1)); » 1. Interface fonctionnelle = interface avec une unique m´ ethode abstraite

9/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(10)

2.3 Exemples de lambda expressions

■ Types des arguments explicites (1, 4) ou inf´ er´ es (2, 5, 6)

Pas de m´ elange entre « explicite » et « inf´ er´ e »

■ Le corps peut ˆ etre un bloc (6) ou une expression (1–5)

Bloc retournant une valeur (dit value-compatible) ou rien (dit void-compatible)

• Idem pour l’expression : une valeur (1, 2, 3, 5) ou rien (4)

■ Un seul argument = ⇒ possible d’omettre les parenth` eses autour de l’argument

10/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

1. (int x, int y) -> x + y

// retourne la somme des deux arguments

2. (x, y) -> x - y

// retourne la diff´erence

3. () -> 42

// pas d’argument, retourne42

4. (String s) -> System.out.println(s)

// affiche l’argument et ne retourne rien

5. x -> 2 * x

// un argument (sans parenth`ese)

6. c ->

{

int s = c.size(); c.clear(); return s;

} // type de l’argument poss´edant les m´ethodes size()etclear(), p.ex. une collection

(11)

2.4 Contexte d’ex´ ecution d’une lambda expres- sion

■ Une lambda expression s’ex´ ecute dans un contexte

• Comme attribut de classe : class Bar { Foo foo = () -> 42; }

• Comme variable locale : void bar() { Foo foo = () -> 42; } ;

■ Elle peut utiliser les variables de son contexte, y compris « this » lorsqu’elle est imbriqu´ ee dans une instance de classe

■ R` egles classiques d’utilisation et de nommage des ´ el´ ements du contexte

• Un exemple l´ egal : l’argument « i » de la lambda cache l’attribut « i »

− class Bar { int i; Foo foo = i -> i * 2; } ;

• Un exemple ill´ egal : « i » est d´ ej` a une variable locale de « bar »

− void bar() { int i; Foo foo = i -> i * 2; } ;

11/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(12)

2.5 R´ ef´ erence de m´ ethode*

■ Cas particulier d’une lambda expression avec un seul argument

+ l’expression est un unique appel ` a une m´ ethode avec un seul argument

• Par exemple : str -> Integer.parseInt(str)

• Simplification de l’´ ecriture avec la forme « r´ ef´ erence de m´ ethode »

− Pour le mˆ eme exemple : Integer::parseInt

■ Plus g´ en´ eralement, une lambda expression peut ˆ etre repr´ esent´ ee par une m´ ethode concr` ete d’une classe

= ⇒ Une r´ ef´ erence de m´ ethode est un raccourci d’´ ecriture d’une lambda expression avec un argument et l’expression form´ ee de l’appel unique de la m´ ethode r´ ef´ erenc´ ee

■ Syntaxe (plus d’informations dans le document « pour aller plus loin »)

ReferenceType::identifier pour m´ ethode de classe, p.ex. « Integer::parseInt »

ObjectReference::identifier pour m´ ethode d’instance : p.ex. « System.out::println »

ReferenceType::new pour constructeur, p.ex. « ArrayList::new »

12/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(13)

2.6 Interfaces fonctionnelles standard*

■ java.util.function

[PackageJavaUtilFunction, JSE8]

• Plus de 40 fonctions

− Dont 6 de base : Operator, Predicate, Function, Supplier, Consumer

− Avec des variantes pour les types primitifs

Interface Signature

la fonction

Exemple

1 UnaryOperator<T> T apply(T t) String::toLowerCase 2 BinaryOperator<T> T apply(T t1, T, t2) BigInteger::add 3 Predicate<T> boolean test(T t) Collection::isEmpty 4 Function<T, R> R apply(T t) Arrays::asList 5 BiFunction<T, U, R> R apply(T t, U u) (x, y) -> x - y

6 Supplier<T> T get() Instant::now

7 Consumer<T> void accept(T t) System.out::println 8 ToIntFunction<T> int applyAsInt(T t) Integer::parseInt 9 IntFunction<R> R apply(int i) int[]::new

■ Pour chaque ligne du tableau, on peut ´ ecrire

« colonne Interface » ref = « colonne Exemple »

P.ex. Function<ArrayList, List> obj = Arrays::asList;

13/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(14)

2.6.1 Exemples d’utilisation (de base)

Classeseance8/InterfaceFonctionnelleStandard

1 // i n t e r f a c e s f o n c t i o n n e l l e s de b a s e

2 U n a r y O p e r a t o r < String > f1 = S t r i n g :: t o L o w e r C a s e ; 3 S y s t e m . out . p r i n t l n ( f1 . a p p l y ( " ABC " ) ) ; //

4 B i n a r y O p e r a t o r < B i g I n t e g e r > f2 = B i g I n t e g e r :: add ;

5 B i g I n t e g e r a = n e w B i g I n t e g e r ( " 2 " ) , b = n e w B i g I n t e g e r ( " 3 " ) ; 6 S y s t e m . out . p r i n t l n ( f2 . a p p l y ( a , b ) ) ; //

7 P r e d i c a t e < C o l l e c t i o n < String > > f3 = C o l l e c t i o n < String >:: i s E m p t y ; 8 S y s t e m . out . p r i n t l n ( f3 . t e s t (n e w A r r a y L i s t < String >() ) ) ; //

9 F u n c t i o n < S t r i n g [] , List < String > > f4 = A r r a y s :: a s L i s t ; 10 S y s t e m . out . p r i n t l n ( f4 . a p p l y (n e w S t r i n g [] { " a " , " b " }) ) ; //

11 S u p p l i e r < Instant > f5 = I n s t a n t :: now ; 12 S y s t e m . out . p r i n t l n ( f5 . get () ) ; //

13 C o n s u m e r < String > f6 = S y s t e m . out :: p r i n t l n ; 14 // v a r i a n t e p o u r les t y p e s p r i m i t i f s

15 T o I n t F u n c t i o n < String > f7 = I n t e g e r :: p a r s e I n t ; 16 I n t F u n c t i o n <i n t[] > f8 = i n t[ ] : :n e w;

17 f6 . a c c e p t ( " abc " ) ; S y s t e m . out . p r i n t l n ( f7 . a p p l y A s I n t ( " 11 " ) ) ; //

18 i n t[] t = f8 . a p p l y (4) ; S y s t e m . out . p r i n t l n ( t . l e n g t h ) ; //

Affichage :

«abc», puis «5», «true», «[a, b]», «2019-03-13T21:06:26.529Z», «abc», «11», et enfin «4»

14/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(15)

3 Utilisation dans les tests JUnit

■ Le second argument de la m´ ethode de classe Assert.assertThrows est une expression lambda

• Expression de type ThrowingRunnable, qui est une interface fonctionnelle

• L’expression n’a pas d’argument en entr´ ee : « () »

• L’expression ex´ ecute une m´ ethode qui ne retourne aucune valeur : « void »

Lev´ ee d’une exception AssertionError si l’expression lambda ne l` eve pas d’exception

Classeseance6.mediathequesimplifie.testdevalidation.TestAjouterLocalisation 1 @ T e s t

2 p u b l i c v o i d t e s t A j o u t e r L o c a t i o n T e s t 4 P u i s 3 () t h r o w s O p e r a t i o n I m p o s s i b l e { 3 m e d i a t h e q u e . a j o u t e r L o c a l i s a t i o n ( " s1 " , " r1 " ) ;

4 A s s e r t . a s s e r t T h r o w s ( O p e r a t i o n I m p o s s i b l e .class,

5 () - > m e d i a t h e q u e . a j o u t e r L o c a l i s a t i o n ( " s1 " , " r1 " ) ) ; 6 }

• OperationImpossible

assertThrows(Class<OperationImpossible>, ThrowingRunnable)

− Avec

public interface ThrowingRunnable

{

void run() throws Throwable;

}

. Depuis JUnit version 4.13.

15/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(16)

4 Utilisation dans la manipulation des collections : les Streams

4.1 Retour sur les motivations et les objectifs des lambda expressions 4.2 Pipeline, stream, et ´ evaluation tardive

4.3 Quelques exemples

. Les ´ el´ ements de cette section sont extraits des r´ ef´ erences

[Naftalin, M., 2012]

,

[Naftalin, 2015]

, et

[Bloch, 2018]

16/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(17)

4.1 Retour sur les motivations et les objectifs des lambda expressions

■ Motivation 1 : introduire des ´ elements de programmation orient´ ee fonction

■ Motivation 2 : raccourcir, les nouveaux sucres syntaxiques « -> » et « :: »

■ Motivation 3 : permettre des ex´ ecutions parall` eles

• C’est cette motivation qui donne la biblioth` eque des Streams

Imaginons une collection de grande taille ET un ordinateur avec bcp de cœurs

− Mise en œuvre du paradigme de programmation « Map/Reduce »

17/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

double maxDistance =

pointList.parallelStream()

.map(p -> p.distance(0, 0)) .reduce(Double::max) .orElse(0.0);

fork

fork fork

map map map map

join

reduce reduce

join join

reduce

(18)

4.2 Pipeline, stream, et ´ evaluation tardive

■ Philosophie UNIX : « At its heart is the idea that the power of a system comes more from the relationships among programs than from the programs themselves.

Many UNIX programs do quite trivial things in isolation, but, combined with other programs, become general and useful tools. »

[Kernighan and Pike, 1984]

Les lambda expressions = traitements ` a granularit´ e fine et composables

■ Pipeline = « d´ ebut » + « traitement interm´ ediaire » + « terminaison »

• Description d´ etaill´ ee dans le document « pour aller plus loin »

Stream = S´ equence de valeurs, ordonn´ ees ou non, et non stock´ ees

■ Pipeline de streams + ´ evaluation tardive

• C’est l’op´ eration terminale qui « tire » les valeurs

− Aucune valeur n’est calcul´ ee tant qu’elle n’est pas demand´ ee

IntStream.iterate(1, i -> i * 2) // g´ en´ eration

stream

de taille infinie .limit(10) // limitation du nombre de g´ en´ erations

.forEach(System.out::println) // op´ eration qui « tire » les valeurs

18/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(19)

4.3 Quelques exemples I

■ D´ ebut : g´ en´ eration d’une s´ equence infinie avec IntStream.iterate

Interm´ ediaire : troncature avec limit + insertion d´ everminage avec peek

Terminaison : test de pr´ esence avec anyMatch

■ D´ emonstration de l’´ evaluation tardive

Classeseance8/lambdaexpressions/ExampleNaftalin2015

1 b o o l e a n t r o u v e = I n t S t r e a m . i t e r a t e (1 , i - > i * 2)

2 . l i m i t ( 1 0 )

3 . p e e k ( S y s t e m . out :: p r i n t l n )

4 . a n y M a t c h ( v - > v == 16) ;

Affichage :

1 2 4 8 16

19/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(20)

4.3 Quelques exemples II

■ D´ ebut : stream

de

Collection

Interm´ ediaire : filtrage avec filter

Terminaison : recherche d’un ´ el´ ement avec findFirst

■ Recherche dans une collection avec filtrage + obtention de la premi` ere valeur trouv´ ee

Hypoth` ese : la pr´ econdition du cas d’utilisation « ajouter un genre » inclut la condition « genre avec ce nom inexistant »

Classeetudesdecas/mediathequeaveclambdasoptionaletstreams/Mediatheque

1 /* *

2 * c h e r c h e r G e n r e c h e r c h e un G e n r e d a n s la l i s t e des g e n r e s .

3 *

4 * @ p a r a m n o m G e n r e du G e n r e a c h e r c h e r

5 * @ r e t u r n le g e n r e c o r r e s p o n d a n t au nom d a n s la c o l l e c t i o n

6 */

7 p r i v a t e O p t i o n a l < Genre > c h e r c h e r G e n r e (f i n a l S t r i n g n o m G e n r e ) { 8 r e t u r n l e s G e n r e s . s t r e a m () . f i l t e r ( g - > g . g e t N o m () . e q u a l s ( n o m G e n r e ) ) .

f i n d F i r s t () ; 9 }

La classe Optional est ´ etudi´ ee dans la section qui suit celle-ci.

20/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(21)

4.3 Quelques exemples III

■ D´ ebut : stream

de

Collection

Interm´ ediaire : filtrage avec filter

Terminaison : test de pr´ esence avec anyMatch

■ Existe-t-il un document avec le genre donn´ e ?

Classeetudesdecas/mediathequeaveclambdasoptionaletstreams/Mediatheque

1 /* *

2 * c h e r c h e un d o c u m e n t d o n t le g e n r e est i n d i q u e en p a r a m e t r e .

3 *

4 * @ p a r a m g G e n r e du d o c u m e n t a c h e r c h e r 5 * @ r e t u r n t r u e s ’ il en e x i s t e un f a l s e s i n o n

6 */

7 p r i v a t e b o o l e a n e x i s t e D o c u m e n t (f i n a l G e n r e g ) {

8 r e t u r n l e s D o c u m e n t s . v a l u e s () . s t r e a m () . a n y M a t c h ( d - > d . g e t G e n r e () . e q u a l s ( g ) ) ; 9 }

21/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(22)

4.3 Quelques exemples IV

■ D´ ebut : g´ en´ eration d’une s´ equence infinie avec IntStream.iterate

Interm´ ediaire : troncature avec limit + transformation avec mapToObj

Terminaison : r´ eduction avec collect en une liste avec toList

de

Collectors

■ Collecte dans une liste

Classeseance8/lambdaexpressions/ExampleNaftalin2015

1 List < String > l = I n t S t r e a m . i t e r a t e (1 , i - > i * 2)

2 . l i m i t ( 1 0 )

3 . m a p T o O b j ( S t r i n g :: v a l u e O f )

4 . c o l l e c t ( C o l l e c t o r s . t o L i s t () ) ;

5 S y s t e m . out . p r i n t l n ( l ) ;

Affichage :

[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

■ Cet exemple d´ emontre implicitement une construction d’objet

• On pourrait ´ ecrire mapToObj(Integer::new) pour r´ ecup´ erer une List<Integer>

22/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(23)

4.3 Quelques exemples V

■ D´ ebut : g´ en´ eration d’une s´ equence infinie avec IntStream.iterate

Interm´ ediaire : troncature avec limit + transformation avec mapToObj

Terminaison : r´ eduction avec collect en une chaˆıne de caract` eres avec

joining

de

Collectors

■ Collecte dans une chaˆıne de caract` eres

Classeseance8/lambdaexpressions/ExampleNaftalin2015

1 S t r i n g s = I n t S t r e a m . i t e r a t e (1 , i - > i * 2)

2 . l i m i t ( 1 0 )

3 . m a p T o O b j ( S t r i n g :: v a l u e O f )

4 . c o l l e c t ( C o l l e c t o r s . j o i n i n g ( " ␣ + ␣ " ) ) ; 5 S y s t e m . out . p r i n t l n ( s ) ;

Affichage :

1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 + 256 + 512

23/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(24)

4.3 Quelques exemples VI

■ D´ ebut : g´ en´ eration d’un stream

Terminaison : application d’un effet de bord avec forEach

■ Exemple d’application d’un effet de bord

Classeseance8/lambdaexpressions/ExampleNaftalin2015

1 List < Point > p o i n t s = A r r a y s . a s L i s t (n e w P o i n t (1 , 2) , n e w P o i n t (2 , 4) ) ; 2 S y s t e m . out . p r i n t l n ( p o i n t s ) ;

3 p o i n t s . s t r e a m () . f o r E a c h ( p - > p . t r a n s l a t e (1 , 2) ) ; 4 S y s t e m . out . p r i n t l n ( p o i n t s ) ;

Affichage :

[java.awt.Point[x=1,y=2], java.awt.Point[x=2,y=4]]

[java.awt.Point[x=2,y=4], java.awt.Point[x=3,y=6]]

24/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(25)

4.3 Quelques exemples VII

■ D´ ebut : g´ en´ eration de deux streams

Interm´ ediaire : concat´ enation des deux streams avec concat

de

Stream

+ retrait des doublons avec distinct

Terminaison : collecte dans un ensemble avec toSet

■ D´ emonstration de la concat´ enation de streams

Classeseance8/lambdaexpressions/ExampleNaftalin2015

1 List < List < String > > l i s t e D e L i s t e s = n e w A r r a y L i s t < >() ; 2 l i s t e D e L i s t e s . add ( A r r a y s . a s L i s t ( " a " , " b " , " c " ) ) ; 3 l i s t e D e L i s t e s . add ( A r r a y s . a s L i s t ( " c " , " d " , " a " ) ) ;

4 Set < String > c o n c a t = S t r e a m . c o n c a t ( l i s t e D e L i s t e s . get (0) . s t r e a m () ,

5 l i s t e D e L i s t e s . get (1) . s t r e a m () )

6 . d i s t i n c t ()

7 . c o l l e c t ( C o l l e c t o r s . t o S e t () ) ;

8 S y s t e m . out . p r i n t l n ( c o n c a t ) ;

Affichage :

[a, b, c, d]

Le prototype de la m´ethodeasListdeArraysest «List<String> asList(String... a)». Pour rappel, l’´ecriture «String...» est une commodit´e d’´ecriture est appell´eevarargs.

25/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(26)

4.3 Quelques exemples VIII

■ Mˆ eme exemple avec g´ en´ eralisation ` a un nombre quelconque de listes

ebut : obtention de la s´ equence de listes de la liste englobante

Interm´ ediaire : transformation de chaque liste de String en un stream avec stream

de

List et insertion dans une s´ equence de String

− flatMap = flattened map

• Retourne un Stream<String> au lieu d’un Stream<Stream<String>>

Classeseance8/lambdaexpressions/ExampleNaftalin2015

1 List < List < String > > l i s t e D e L i s t e s = n e w A r r a y L i s t < >() ; 2 l i s t e D e L i s t e s . add ( A r r a y s . a s L i s t ( " a " , " b " , " c " ) ) ; 3 l i s t e D e L i s t e s . add ( A r r a y s . a s L i s t ( " c " , " d " , " a " ) ) ; 4 Set < String > f l a t M a p = l i s t e D e L i s t e s . s t r e a m ()

5 . f l a t M a p ( L i s t :: s t r e a m )

6 . d i s t i n c t ()

7 . c o l l e c t ( C o l l e c t o r s . t o S e t () ) ;

8 S y s t e m . out . p r i n t l n ( f l a t M a p ) ;

26/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(27)

5 Utilisation dans la gestion des r´ ef´ erences null : Optional

5.1 Probl` eme des r´ ef´ erences null

5.2 Solution non satisfaisante : documentation 5.3 Solution/idiome JAVA : classe Optional

27/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(28)

5.1 Probl` eme des r´ ef´ erences null

■ Situations dans lesquelles « pointeur null » signifie « absence de valeur »

• P.ex. valeur de retour pouvant ˆ etre null

Classeseance8/lambdaoptional/DocumentSansOptional

1 p u b l i c S t r i n g g e t N o m S o u s G e n r e () { 2 S t r i n g r e s u l t = " i n c o n n u " ;

3 if ( g e n r e != n u l l) { // a t t r i b u t p o u v a n t e t r e n u l l 4 S o u s G e n r e sg = g e n r e . g e t S o u s G e n r e () ;

5 if ( sg != n u l l) { // v a r i a b l e p o u v a n t e t r e n u l l 6 S t r i n g n = sg . g e t N o m () ;

7 if ( n != n u l l) { // i n u t i l e si l ’ i n v a r i a n t le v e r i f i e

8 r e s u l t = n ;

9 }

10 }

11 }

12 r e t u r n r e s u l t ; 13 }

28/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

SousGenre

Genre nom:string nbEmprunts:integer=0

Document code:string titre:string auteur:string

correspond

0..1

nom:string nbEmprunts:integer=0

0..1

possède

*

getSousGenre()

(29)

5.2 Solution non satisfaisante : documentation

■ Besoin d’avertir le programmeur de la m´ ethode appelante

• Premier essai : utiliser la documentation Javadoc

Classeseance8/lambdaoptional/GenreSansOptional

1 /* *

2 * o b t i e n t le sous - g e n r e .

3 *

4 * @ r e t u r n le sous - genre , qui p e u t e t r e { @ c o d e n u l l }.

5 */

6 p u b l i c S o u s G e n r e g e t S o u s G e n r e () { 7 r e t u r n s o u s G e n r e ;

8 }

29/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(30)

5.3 Solution/idiome JAVA : classe Optional

■ La solution/l’idiome JAVA :

• Similairement ` a d’autres langages comme Groovy ou Scala,

JAVA propose depuis la version 8 un idiome pour rendre explicite la possibilit´ e qu’une r´ ef´ erence puisse ˆ etre null

et ainsi alerter le programmeur pour qu’il ´ evite le d´ er´ ef´ erencement dans ce cas

− P.ex. : Optional<SousGenre> getSousGenre()

• Pour votre culture g´ en´ erale, conf´ erence de C.A.R. Hoare, qui en 1965 a introduit le concept de « r´ ef´ erence null », ce qu’il consid` ere maintenant comme une erreur :

− Conf´ erence en 2009 : « Null References: The Billion Dollar Mistake »

30/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(31)

5.3.1 Classe Optional

■ Classe conteneur et param´ etr´ ee par le type du contenu : Optional<T>

■ Pas de constructeur, mais cr´ eation par m´ ethodes de classes dites

« fabriques » (factories)

• Optional<Genre> g = Optional.of(genre) :

valeur null non autoris´ ee (exception NullPointerException )

• Optional<Genre> g = Optional.ofNullable(genre) : valeur null autoris´ ee

• Optional<Genre> g = Optional.empty() : contient null

■ Des m´ ethodes pour r´ ecup´ erer la valeur ou tester si null

g.isPresent()

: retourne false si contenu null

g.get()

: l`eve l’exception

NoSuchElementException

si contenu

null

g.orElse("inconnu")

: retourne contenu non null , sinon "inconnu"

■ Des m´ ethodes pour manipuler la valeur si non null

sg.map(SousGenre::getNom)

: applique la lambda expression si non null et retourne la valeur dans un Optional (p.ex. ici, un Optional<String> )

sg.flatMap(SousGenre::getNom)

: idem map , mais sans mettre le r´ esultat dans un Optional (p.ex. ici retourne un String )

31/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(32)

5.3.2 O` u mettre Optional ?

■ « Optional is primarily intended for use as a method return type where there is a clear need to represent “no result,” and where using null is likely to cause errors. »

[Class Optional, JSE8]

■ « The intention of the Optional class is not to replace every single null reference »

[Urma, 2014]

■ Dans le module CSC4102, Optional en guise de valeur de retour lorsque null est fonctionnellement possible (pas un cas d’erreur)

Classeseance8/lambdaoptional/GenreAvecOptional

1 /* *

2 * o b t i e n t le sous - g e n r e .

3 *

4 * Le d i a g r a m m e de c l a s s e s s p e c i f i e qu ’ un sous - g e n r e est o p t i o n n e l .

5 *

6 * @ r e t u r n le sous - genre , qui p e u t e t r e { @ c o d e n u l l }.

7 */

8 p u b l i c O p t i o n a l < S o u s G e n r e > g e t S o u s G e n r e () { 9 r e t u r n O p t i o n a l . o f N u l l a b l e ( s o u s G e n r e ) ; 10 }

32/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(33)

5.3.3 Manipulation d’un objet Optional (1/2)

■ Mˆ eme exemple qu’au d´ ebut de la section avec imbrication de if

isPresent : retourne true si un objet est pr´ esent

get : retourne la valeur pr´ esente, sinon l` eve l’exception NoSuchElementException

Classeseance8/lambdaoptional/DocumentAvecOptional1

1 p u b l i c S t r i n g g e t N o m S o u s G e n r e () { 2 S t r i n g r e s u l t = " i n c o n n u " ; 3 if ( g e t G e n r e () . i s P r e s e n t () ) {

4 O p t i o n a l < S o u s G e n r e > sg = g e n r e . g e t S o u s G e n r e () ; 5 if ( sg . i s P r e s e n t () ) {

6 S t r i n g n = sg . get () . g e t N o m () ;

7 if ( n != n u l l) { // i n u t i l e si l ’ i n v a r i a n t le v e r i f i e

8 r e s u l t = n ;

9 }

10 }

11 }

12 r e t u r n r e s u l t ; 13 }

33/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(34)

5.3.4 Manipulation d’un objet de Optional (2/2)

■ Meilleur code

Classeseance8/lambdaoptional/DocumentAvecOptional2 1 p u b l i c S t r i n g g e t N o m S o u s G e n r e () { 2 r e t u r n g e t G e n r e ()

3 . f l a t M a p ( G e n r e A v e c O p t i o n a l :: g e t S o u s G e n r e ) 4 . map ( S o u s G e n r e :: g e t N o m )

5 . o r E l s e ( " i n c o n n u " ) ; 6 }

• Utilisation de flatMap, map, et orElse

− GenreAvecOptional::getSousGenre retourne un Optional<SousGenre>

− D’o` u,

getGenre().map(GenreAvecOptional::getSousGenre)

retournerait un objet de type

Optional<Optional<SousGenre>>

− Donc, flatMap pour obtenir un objet de type Optional<SousGenre> au lieu d’un objet de type Optional<Optional<SousGenre>>

flatMap : This method is similar to map(Function), but the mapping function is one whose result is already an Optional, and if invoked, flatMap does not wrap it within an additional Optional

[Class Optional, JSE8]

− orElse : retourne la valeur si pr´ esente (≡ get ), sinon une valeur par d´ efaut

34/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(35)

6 Streams + Optional

■ R` egle 45 de « Effective JAVA »

[Bloch, 2018]

: « Use streams judiciously »

« Overusing streams makes programs hard to read and maintain »

Classeetudesdecas/mediathequeaveclambdasoptionaletstreams/Mediatheque

1 p r i v a t e O p t i o n a l < F i c h e E m p r u n t > c h e r c h e r E m p r u n t (f i n a l S t r i n g nom , f i n a l S t r i n g prenom , f i n a l S t r i n g c o d e ) t h r o w s O p e r a t i o n I m p o s s i b l e {

2 r e t u r n l e s E m p r u n t s

3 . s t r e a m ()

4 . f i l t e r ( f - > f . c o r r e s p o n d (

5 l e s C l i e n t s . v a l u e s () . s t r e a m ()

6 . f i l t e r ( c - > c . g e t N o m () . e q u a l s ( nom ) && c . g e t P r e n o m () . e q u a l s ( p r e n o m ) )

7 . f i n d F i r s t ()

8 . o r E l s e T h r o w (() - > n e w I l l e g a l A r g u m e n t E x c e p t i o n ( 9 " pas ␣ de ␣ c l i e n t ␣ ’ " + nom + " ␣ " + p r e n o m + " ’ " ) ) ,

10 l e s D o c u m e n t s . v a l u e s () . s t r e a m ()

11 . f i l t e r ( d - > d . g e t C o d e () . e q u a l s ( c o d e ) )

12 . f i n d F i r s t ()

13 . o r E l s e T h r o w (() - > n e w I l l e g a l A r g u m e n t E x c e p t i o n (

14 " pas ␣ de ␣ d o c u m e n t ␣ ’ " + c o d e + " ’ " ) ) ) )

15 . f i n d F i r s t () ;

16 }

35/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(36)

7 Mise en pratique en TP (2h) + HP (3h)

■ Utilisation des Streams et de Optional dans certaines parties du code

■ Continuation du d´ eveloppement de l’application de l’´ etude de cas

■ Rendu de la s´ eance en HP (3h) : PDF + JAVA dans « sprint2 »

■ Compl´ ements « Pour aller plus loin » sur les lambda expressions et les Streams

36/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

(37)

ef´ erences I

Bloch, J. (2018).

Effective Java, 3rd Edition.

Addison-Wesley.

Class Optional (JSE8).

Javadoc of the class java.util.Optional of JAVA 9.

https:

//docs.oracle.com/javase/9/docs/api/index.html?java/util/Optional.html.

Kernighan, B. and Pike, R., editors (1984).

The UNIX Programming Environment.

Prentice-Hall.

Naftalin, M. (2015).

Mastering Lambdas : Java Programming in a Multicore World.

Mc Graw Hill, Oracle Press.

Naftalin, M. (2012).

The Lambda FAQ.

http://www.lambdafaq.org/.

37/38 01/2022 Denis Conan CSC4102 :Lambda expressions,StreamsetOptional

(38)

ef´ erences II

PackageJavaUtilFunction (JSE8).

Javadoc of the package java.util.function of JAVA SE 8.

https://docs.oracle.com/javase/9/docs/api/java/util/function/

package-summary.html.

Saumont, P.-Y. (2017).

Functional Programming in Java—How functional techniques improve your Java programs.

Manning.

Urma, R.-G. (2014).

Tired of Null Pointer Exceptions ? Consider Using Java SE 8’s Optional !

https:

//www.oracle.com/technetwork/articles/java/java8-optional-2175753.html.

38/38 01/2022 Denis Conan CSC4102 :Lambda expressions,Streamset

Références

Documents relatifs

− d’appliquer des patrons (motifs) de conception et de programmation (idiomes) donn´ es dans le but d’am´ eliorer la qualit´ e du logiciel 2.. Qualit´ e logicielle et

26/36 01/2022 Denis Conan CSC4102 : Programmation Java et construction de logiciel La classe E doit implémenter Comparable&lt;E&gt;. Pas de méthode get get(int index)

• sépare les données modifiables (références, tableaux, chaînes de caractères, enregistrements) dans des monades. • les monades peuvent utiliser tous les termes, mais seuls les

exceptionnellement comme valeur d’une affectation Elle ´ evite de cr´ eer des fonctions ` a usage

note_cc1 = float(input('Note du premier contrôle : ')) note_cc2 = float(input('Note du second contrôle : ')) note_exam = float(input(&#34;Note de l'examen : &#34;)) moyenne_cc

• Chaque classe enveloppe poss`ede des m´ethodes pour extraire la valeur d’un objet : primitifValue() appliqu´ee sur l’objet enveloppe renvoie une valeur de type primitif.. •

• Chaque classe enveloppe poss`ede des m´ethodes pour extraire la valeur d’un objet : primitifValue() appliqu´ee sur l’objet enveloppe renvoie une valeur de type primitif.. •

• Si la classe Rect est derivée de la classe Shape, une operation qui peut être exécutée sur un objet de la classe Shape peut aussi être exécutée sur un objet de la classe