Vous êtes sur la page 1sur 8

Java 8 JSR-335 1/3 Expressions Lambda | S...

http://blog.soat.fr/2012/11/java-8-jsr-335-13-exp...

Be smart, enjoy coding !


Agilit

1 of 8

OK
Java

.NET

Web

Mobilit

Divers

Build 2015

11/11/2015 19:48

Java 8 JSR-335 1/3 Expressions Lambda | S...

http://blog.soat.fr/2012/11/java-8-jsr-335-13-exp...

Accueil > Java > Java 8 JSR-335 1/3 Expressions Lambda

NOUS SOUTENONS

JAVA 8 JSR-335 1/3


EXPRESSIONS LAMBDA
Par Yohan BESCHI

28 novembre 2012

Neuf ans aprs les Generics et Collections de Java 5, les expressions Lambda
seront la nouvelle rvolution dans le monde de Java (version 8). Pour le
meilleur ou pour le pire vous den juger !

SOAT

Le projet Lambda [1] a pour objectif daccueillir un prototype de


limplmentation de la JSR-335 (Lambda Expressions for the Java Programming
Language [2]) qui sera incluse dans la JDK 8, limplmentation de rfrence de
Java SE 8.
Pour une explication gnraliste des expressions Lambda (nommes aussi fonctions anonymes ou

Site Soat
Google+
Twitter Soat
Twitter Soat Agile
Twitter Soat Experts .Net
Twitter Soat Experts Java

closures), je vous invite consulter la page wikipedia consacre au sujet [3].


Comme nous le verrons par la suite, la JSR-335 nest pas limite aux expressions Lambda, elle dnit
aussi laliasing de mthodes et de constructeurs par rfrence, ainsi que lajout de mthodes par
dfaut dans les interfaces.
Note importante : La JSR ntant pas encore ltat nal , il est possible quil y ait des dirences
entre les fonctionnalits dcrites dans cet article et les fonctionnalits proposes dans la version
nale.
Pour cet article la JDK 8 build b64 avec support des lambdas a t utilise. Le dernier build peut tre
tlcharg depuis java.net.
Lintgralit des sources est disponible via Github.

GETTING STARTED
Commenons par un exemple simple, en implmentant une mthode buildMessage(), qui prend une
chane de caractres en paramtres et qui retourne une chane de caractres.
Pour que larticle reste lisible, la javadoc, les noms de packages et les imports ont t omis dans
tous les exemples.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

/ **
* org.isk.gettingstarted.FirstFunctionalInterface.java
*/
public interface FirstFunctionalInterface {
String buildMessage(String msg);
}
/ **
* org.isk.gettingstarted.GettingStartedTest.java
*/
public class GettingStartedTest {
@Test
public void oldWayWithAnonymousClass() {
final FirstFunctionalInterface firstInterface = new FirstFunctionalInterface() {
@Override
public String buildMessage(String msg) {
return "Hello " + msg;
}
};
final String string = firstInterface.buildMessage("Carl");
}

Assert.assertEquals("Hello Carl", string);

@Test
public void newWayWithLambdaExpression() {
final FirstFunctionalInterface firstInterface = msg ->
"Hello " + msg + " with a lambda expression"
final String string = firstInterface.buildMessage("John");

SOAT PARTAGE
AppCircle
Appli de rfrence SoGames
Appli de rfrence SoMvc
Developpez.com
GitHub Soat
Happy .Net
Son expertise
SoPrism
YouTube

NUAGE DE MOTS
CLS
.NET agile Agilit ASP .NET

bytecode C# Cloud confrence

devoxx devoxx france 2012


Html5

Java Javascript jvm

jvmhardcore Kanban Microsoft


pjba plume Scrum Silverlight

Techdays web Windows 8

Windows Phone

AUTHENTIFICATION

LICENCE

Sauf mention contraire, le contenu


de ce blog est mis disposition
selon les termes de la licence
Creative Commons.

Assert.assertEquals("Hello John with a lambda expression", string);

Lun des objectifs des expressions Lambda est dliminer la verbosit des classes anonymes.
Comme nous pouvons le constater, cest mission accomplie. Lutilisation dune classe anonyme
prend 5 lignes (6 avec lannotation @Override ) alors que lexpression Lambda nen prend quune

2 of 8

11/11/2015 19:48

Java 8 JSR-335 1/3 Expressions Lambda | S...

http://blog.soat.fr/2012/11/java-8-jsr-335-13-exp...

seule.
A premire vue, la structure dune fonction Lambda est dconcertante. Le nouvel oprateur ->
dlimite les paramtres du corps de la mthode [paramtres -> corps de la mthode]. Notre
mthode :
1
2
3

public String buildMessage(String msg) {


return "Hello " + msg;
}

est transforme en :
1

msg -> "Hello " + msg + " with a lambda expression";

o msg est le paramtre (le type est implicite, mais il peut tre explicite si ncessaire), loprateur ->
marque la n de la dclaration des paramtres et le dbut du corps de la mthode. Le mot cl
return est aussi absent lorsque le corps de la mthode est une expression.

FUNCTIONAL INTERFACES
Une interface fonctionnelle est une interface nayant quune seule mthode abstraite, qui
nappartient pas la classe Object. De plus, toutes les mthodes doivent tre publiques.
Il est important de faire la distinction entre une mthode abstraite et une signature de mthode qui,
selon la dnition de la JLS [4], ninclue que le nom de la mthode et ses paramtres. La valeur de
retour, ainsi que les exceptions, nen font pas partie.
A noter que rien de particulier ne doit tre fait pour quune interface devienne une interface
fonctionnelle, le compilateur a la charge de les identier daprs leur structure.
1
2
3
4
5
6
7
8
9
10
11
12
13

// Interface fonctionnelle
// equals() appartient la classe java.lang.Object et est publique
public interface Comparator<T> {
boolean equals(Object obj);
int compare(T o1, T o2);
}
// Nest pas une interface fonctionnelle
// Bien que clone() appartienne la classe java.lang.Object, elle nest pas publique
public interface Foo {
int doSomething();
Object clone();
}

La JDK contient dj des interfaces rpondant cette dnition, auparavant nomms SAM Types
(Single Abstract Method). Elles sont parfaitement adaptes pour tre utilises avec les nouvelles
fonctionnalits Lambda. Les suivantes tant le plus souvent utilises :
java.util.Comparator
java.lang.Runnable
java.awt.event.ActionListener
javax.swing.event.ChangeListener

Pour plus de dtails sur les interfaces fonctionnelles notamment sur la rsolution de lhritage
dinterfaces -, vous pouvez consulter la JSR Part A.

EXPRESSIONS LAMBDA
DFINITION
En Java, une expression Lambda est une forme de mthode, plus compacte quune mthode
standard, pour laquelle le nom est implicite (ce nest jamais une fonction anonyme comme on peut
le rencontrer dans dautres langages puisque nous avons besoin dune interface fonctionnelle). De
plus, les paramtres peuvent tre omis, tout comme leur type ou une valeur de retour.
Comme voqu dans la section Getting Started , le principal problme des classes anonymes est
leur verbosit, ce que les expressions Lambda tentent de gommer.
Regardons quelques exemples dexpressions Lambda [5] :
// 1. Prend un numrique et retourne sa valeur double
x -> 2
* x
// 2. Prend deux int et retourne leur somme
(int x, int y) -> x + y
// 3. Ne prend pas de paramtres et retourne 42
() -> 42
// 4. Prend une chane de caractres, affiche sa valeur et ne retourne rien

3 of 8

11/11/2015 19:48

Java 8 JSR-335 1/3 Expressions Lambda | S...

http://blog.soat.fr/2012/11/java-8-jsr-335-13-exp...

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


// 5. Prend une collection, rcupre sa taille, la vide
// et retourne la taille quelle avait au dbut du bloc
c -> {
int s = c.size();
c.clear();
return s;
}
Le type des paramtres peut tre explicite (exemples 2 et 4) ou implicite (exemples 1 et 5). Cependant, il nest pas
possible de mixer les deux critures dans une expression Lambda.
Les parenthses entourant un, et un seul, paramtre implicite peuvent tre omises (exemples 1 et 5).
Le corps de la mthode peut tre un bloc (encadr par des accolades, exemple 5) ou une expression (exemples 1,
2, 3 et 4).
Si le corps de la mthode est un bloc, il peut retourner une valeur (exemple 5) ou non laide du mot cl return ,
selon le cas.
Si le corps de la mthode est une expression, il peut retourner une valeur (exemples 1,2 et 3) ou non (exemple 4)
selon le cas. Le mot cl return est inutile.

Attention, le problme de verticalit des classes anonymes ne doit pas tre transform en problme
dhorizontalit, comme aurait pu le devenir lexemple 5 qui pourrait tre crit sur une ligne.

CONTEXTE
Le type dune expression Lambda est celui de linterface contenant la mthode implmente par
lexpression Lambda. Une expression Lambda peut avoir dirents types dans dirents contextes.
Il nexiste pas comme dans certains langages un type gnrique Lambda.

GENERICS
Une interface fonctionnelle peut dnir des Generics. En reprenant le tout premier exemple, voici ce
quon peut malheureusement avoir si lon en fait mauvais usage :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

/ **
* org.isk.generics.GenericsLambda.java
*/
public interface GenericsLambda<T, R> {
R doSomething(T t);
}
/ **
* org.isk.generics.GenericsLambdaTest.java
*/
public class GenericsLambdaTest {
@Test
public void genericLambda() {
GenericsLambda<String, String> gl = msg ->
"Hello " + msg + " with a lambda expression"
final String string = gl.doSomething("John");

Assert.assertEquals("Hello John with a lambda expression", string);

Une mthode prenant un Type gnrique I et retournant un Type gnrique O doit tre utilise
dans des situations bien prcises, telles que nous le verrons dans le troisime article de cette srie.
Utiliser une telle mthode pour viter davoir dnir une interface fonctionnelle, et avoir le
sentiment dutiliser une fonction anonyme, est considr comme tant une mauvaise pratique.
De mme, lutilisation dune ellipse en tant que paramtre dune mthode, et donc dune expression
Lambda, doit tre limite au passage dun pseudo tableau dont tous les objets reprsentent la
mme chose (le principe restant que lon passe des lments spars par une virgule, mais dont la
reprsentation dans la mthode ou le corps de lexpression Lambda, est un tableau). La position des
objets dans le tableau, ne doit pas avoir dimportance.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

4 of 8

/ **
* org.isk.generics.GenericsLambda.java
*/
public interface GenericsLambda<T, R> {
R doSomething(T t);
}
/ **
* org.isk.generics.GenericsLambdaWithEllipse.java
*/
public interface GenericsLambdaWithEllipse<T, R> {
R doSomething(T ... t);
}
/ **
* org.isk.generics.GenericLambdaWithEllipseTest.java
*/
public class GenericLambdaWithEllipseTest {
@Test
public void genericLambdaWithEllipse() {
// Construit un message avec le nom, lge et la ville
final GenericsLambdaWithEllipse<Object, String> gle = array -> {
// Retourne un message en fonction de lge

11/11/2015 19:48

Java 8 JSR-335 1/3 Expressions Lambda | S...


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

http://blog.soat.fr/2012/11/java-8-jsr-335-13-exp...

final GenericsLambda<Integer, String> gl = age -> {


if (age.intValue() < 40) {
return "You are young";
} else {
return "You are still young";
}
};

};

return "Hello " + array[0] + ", you live in " + array[2] + " and "
+ gl.doSomething((Integer)array[1]) + "!";

final String string = gle.doSomething("John", 20, "Paris");

Assert.assertEquals("Hello John, you live in Paris and You are young!", string);

Outre la mauvaise utilisation de lellipse, limbrication des expressions Lambdas rend le code
dicilement lisible, et par consquent augmente le risque derreurs et donc de bugs.

DESIGN FIRST
Le fait davoir crer une interface fonctionnelle ce que certains pourraient considrer comme
problmatique -, impose davoir une rexion sur la pertinence dutiliser une expression Lambda.
Si par exemple nous souhaitons eectuer une curryfaction (une rduction de paramtres), utiliser
les expressions Lambda est une trs mauvaise ide, aussi bien en termes de conception que de
lisibilit. Il nest plus question de verbosit.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

/ **
* org.isk.currying.Division.java
*/
public interface Division {
double divide(double x, double y);
}
/ **
* org.isk.currying.Reduction.java
*/
public interface Reduction {
double divide(double x);
}
/ **
* org.isk.currying.CurryingTest.java
*/
public class CurryingTest {
/ **
* Currying without lambda expressions
*/
@Test
public void curryingWithoutLambdaExpression() {
Assert.assertEquals(1.5, this.divideByTwo(3), 0.00001);
Assert.assertEquals(1, this.divideByThree(3), 0.00001);
}
public double divideByTwo(int x) {
return this.divide(x, 2);
}
private double divideByThree(double x) {
return this.divide(x, 3);
}
private double divide(double x, double y) {
return x / y;
}
/ **
* Currying with lambda expressions
*/
@Test
public void curryingWithLambdaExpression() {
final Division reduction = (x, y) -> x / y;
final Reduction divisionByTwo = x -> reduction.divide(x, 2);
final Reduction divisionByThree = x -> reduction.divide(x, 3);

Assert.assertEquals(1.5, divisionByTwo.divide(3), 0.00001);


Assert.assertEquals(1, divisionByThree.divide(3), 0.00001);

PIPELINING
Tout comme il est possible de chaner lappel de mthodes :
1
2

node.run().execute()

il est possible de chaner la dnition dexpressions Lambda :


1
2

5 of 8

Node<FinalNode> node = () -> () -> "ok";

11/11/2015 19:48

Java 8 JSR-335 1/3 Expressions Lambda | S...

http://blog.soat.fr/2012/11/java-8-jsr-335-13-exp...

qui auraient aussi pu tre crites de la faon suivante :


1
2
3
4

() -> {
return () -> "ok";
}

Exemple complet :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

/ **
* org.isk.pipelining.Division.java
*/
public interface Node<T> {
T run();
}
/ **
* org.isk.pipelining.Reduction.java
*/
public interface FinalNode {
String execute();
}
/ **
* org.isk.pipelining.ChainedLambdaTest.java
*/
public class ChainedLambdaTest {
@Test
public void chain() {
Node<FinalNode> node = () -> () -> "ok";

Assert.assertEquals("ok", node.run().execute());

SCOPE DES VARIABLES


Contrairement une classe anonyme, une expression lambda peut tre considre comme un bloc
de code (code encadr par des accolades). Par consquent, toutes les rgles de visibilit des
variables applicables un bloc de code le sont aussi pour une expression lambda, une exception
prs comme nous allons le voir.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

/ **
* org.isk.scope.Executor.java
*/
public interface Executor {
int modify(int v);
}
/ **
* org.isk.scope.Mutable.java
*/
public class Mutable {
public int value;
}
/ **
* org.isk.scope.ScopeTest.java
*/
public class ScopeTest {
private int classField = 1;
private final static int FINAL_STATIC_INT = 2;
private final int FINAL_INT = 3;
@Test
public void scope() {
final Mutable mutable = new Mutable();
mutable.value = 4;
int effectivelyFinalInt = 5;
final int finalInt = 6;
final Executor executor = arg -> {
int localInt = 7;
mutable.value++;
// effectivelyFinalInt++;
return ++this.classField
+ ScopeTest.FINAL_STATIC_INT
+ this.FINAL_INT
+ effectivelyFinalInt
+ finalInt
+ --localInt
+ arg;

};
// effectivelyFinalInt++;

Assert.assertEquals("1", 4, mutable.value);
Assert.assertEquals("2", 31, executor.modify(7));
Assert.assertEquals("3", 5, mutable.value);

// effectivelyFinalInt++;

Dans le corps dune expression Lambda, sont accessibles :

6 of 8

11/11/2015 19:48

Java 8 JSR-335 1/3 Expressions Lambda | S...

http://blog.soat.fr/2012/11/java-8-jsr-335-13-exp...

Les variables dfinies localement ex : localInt


Les variables passes en paramtre ex : arg
Les variables final ( static ou non) ex : FINAL_STATIC_INT , FINAL_INT, mutable et finalInt
Les variables qui sont en ralit final (variables assignes une seule fois et jamais modifies par la suite dans la
mthode contenant lexpression Lambda) ex : effectivelyFinalInt
Les variables de classe (de la classe contenant lexpression Lambda) ex : classField

Seules les variables modies localement sont interdites. Si eectivelyFinalInt est modie dans la
mthode dnissant lexpression Lambda, elle appartient cette catgorie.
this fait rfrence linstance de la classe contenant lexpression Lambda. De mme, super fait
rfrence au parent de cette classe.
A noter que le nom des paramtres de lexpression Lambda doit tre dirent des variables de
classe et des variables locales de la mthode contenant lexpression Lambda.

OBJETS MUABLES
Certains lauront peut-tre remarqu, mais une erreur dicilement identiable peut tre cre.
Si, une variable locale nal, est assigne linstance dune classe (muable ou non), elle ne peut plus
pointer vers une autre rfrence. En revanche, si la classe est muable, les champs de linstance
peuvent tre modis. En dautres termes, nous avons une variable globale la mthode, accessible
et modiable par les expressions Lambda dnies dans cette mthode.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

/ **
* org.isk.mutables.Executor.java
*/
public interface Executor {
int exec();
}
/ **
* org.isk.mutables.Mutable.java
*/
public class Mutable {
public int value;
}
/ **
* org.isk.mutables.MutableTest.java
*/
public class MutableTest {
@Test
public void mutable() {
final Mutable mutable = new Mutable();
mutable.value = 0;
Executor executor = () -> mutable.value++;
Assert.assertEquals("1", 0, mutable.value);
executor.exec();
Assert.assertEquals("2", 1, mutable.value);
executor.exec();
Assert.assertEquals("3", 2, mutable.value);

mutable.value++;
Assert.assertEquals("4", 3, mutable.value);

Les utilisateurs dexpressions Lambda sont diviss en deux groupes : les partisans pour capturer
uniquement des objets immuables dans le corps des expressions Lambda, et les autres pour
lesquels ce nest pas un soucis de capturer des objets muables. Nanmoins, si vous faites partie de
la deuxime catgorie, il faut avoir conscience que prendre en compte toute notion de concurrence
dans le corps dune expression Lambda est dicile, et souvent, posera plus de problmes quil nen
rsoudra.

RESSOURCES
[1] http://openjdk.java.net/projects/lambda/
[2] http://www.jcp.org/en/jsr/summary?id=335
[3] http://en.wikipedia.org/wiki/Anonymous_function
[4] http://docs.oracle.com/javase/specs/
[5] http://www.lambdafaq.org/what-is-a-lambda-expression/
[-] http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html
[-] http://www.lambdafaq.org

7 of 8

11/11/2015 19:48

Java 8 JSR-335 1/3 Expressions Lambda | S...

http://blog.soat.fr/2012/11/java-8-jsr-335-13-exp...

Yohan BESCHI (37 Posts)

ARTICLES SUR LE MME SUJET


[Devoxx FR 2014] Spring 4 dbarque : mise en oeuvre dans une stack Web ractive (mai 12, 2014)
[DevoxxFR 2014] 50 nouvelles choses que lon peut faire avec Java 8 (avr 29, 2014)
DEVOXX, le rendez-vous incontournable des Dveloppeurs JAVA, cest demain et nous y serons ! (avr 15, 2014)
Java sera lhonneur chez Microsoft le 20 mars et vous y tes convis ! (mar 18, 2014)
JDK 8 & Lambdas, Streams et Collectors : la vido et les slides sont sur InfoQ ! (fv 18, 2014)
Like

Tweeter

2 RPONSES JAVA 8 JSR-335 1/3 EXPRESSIONS LAMBDA


1.
Ping : Du nouveau dans la gestion des exceptions avec java 7 ! | Soat blog

2.
Ping : Java 8 Whats new ? 1/3 Project Lambda | Soat blog

LAISSER UN COMMENTAIRE
Votre adresse de messagerie ne sera pas publie. Les champs obligatoires sont indiqus avec *
Nom *

Adresse de contact *

Site web

Commentaire

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b>
<blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Laisser un commentaire

Soat - 87-89, quai Panhard et Levassor 75013 Paris - Tlphone : +33(1) 44 75 42 55 - Tlcopie : +33(1) 44 75 05 25
SA au capital de 80.000 Euros - N Siret : 433 353 760 000 39

8 of 8

11/11/2015 19:48

Vous aimerez peut-être aussi