Lambda expression en Java 8

Lambda calculus is a formal system for functio...

Lambda calculus is a formal system for function definition, function application and recursion introduced by Alonzo Church in the 1930s. (Photo credit: Wikipedia)

Java 8 qui est sur le point de sortir nous promet encore plus de programmation fonctionnelle.

Le parcours  du  tutoriel en ligne justifie cela par l’efficacité de l’approche. Les lambdas expressions permettent en effet de décrire des fonctions anonymes, sans nom et raccrochées à aucun objet. Sans les lambda expression le langage oblige alors à créer une classe (anonyme si nécessaire) et une méthode.  Inutile et superflu parait-il…

Supposons  que l’on veuille pouvoir passer un comportement à une méthode. Comme on n’avait pas de pointeur sur fonction en Java jusque là, on devait définir une interface puis l’implémenter et passer une instance implémentante à la méthode.

Une interface:

public interface Calculator {
        int function(int x);  
}

Une implémentation:

public class InterfaceImplementor implements Calculator {
    Override
    public int function(int x) {
        return 222;
    }
}

définition de la méthode paramétrable par une interface fonctionnelle:

 int calcul(Calculator c){
        return c.function(0); 
  }

L’appel se fait alors par un code (encore du code) du genre:

calcul(new InterfaceImplementor());

On peut éviter de définir une classe en créant une instance d’une classe anonyme:

calcul(new Calculator(){

            @Override
            public int function(int x) {
               return 999;
            }

Le JDK 8 arrive pour éviter encore plus de code en proposant de définir une lambda expression c’est-à-dire une méthode anonyme sans classe. Pour pouvoir tester cette future nouvelle fonctionnalité il faut télécharger le JDK 8 (non finalisé) et Netbean 7.4 (non finalisé) pour pouvoir écrire:

calcul((x) -> 555);

Il y a là une petite complexité (pardon nouveauté) sous le clavier. Le compilateur autorise ici 2 raccourcis: pas d’interface, pas de méthode.  La simple définition d’une fonction qui répond au typage de la méthode de l’interface Calculator suffit pour que le compilateur câble tout correctement. On peut se dire que c’est une bonne chose mais là où ça se complique c’est que Java 8 offre la possibilité d’utiliser une méthode existante sans passer par la case refactoring pour faire rentrer la méthode existante dans le moule d’une interface. Ainsi on peut utiliser n’importe quelle méthode ayant la bonne signature fonctionnelle: dans notre exemple int -> int. L’appel ressemble alors à cela:

calcul(ecxistingObject::existingMethod);

Voici le code complet permettant de voir l’ensemble des évolutions du langage abordées dans ce billet:

Une interface pour la manière de faire « old school »:

package lambda;

public interface Calculator {
        int function(int x);    
}

et son implémentation:

package lambda;

public class InterfaceImplementor implements Calculator{
    @Override
    public int function(int x) {   
       return 222;
    }
}

Une classe existante dont on peut réutiliser une méthode sans avoir à implémenter l’interface vue plus haut:

package lambda;

public class ExistingClass {
 private int i = 777;

 public int uneFonction(int x) {
   return i;
 }
}

Et les différentes manières de passer une fonction à une méthode:

package lambda;

public class Lambda {
 /**
  * @param args the command line arguments
  */
 public static void main(String[] args) {
   // TODO code application logic here

   Lambda l = new Lambda();
   int i = 0;

   // old school, plain class creation

   i = l.calcul(new InterfaceImplementor());
   System.out.println(i);

   // old school, anomymous class

   i = l.calcul(new Calculator(){
           @Override
       public int function(int x) {
         return 999;
       }
     });
   System.out.println(i);

   // anonymous method, lambda expression

   i  = l.calcul((x) -> 555);
   System.out.println(i);

   // method reference !

   ExistingClass existingObject = new ExistingClass();
   i = l.calcul(existingObject::uneFonction);
   System.out.println(i);
 }

 int calcul(Calculator c){
   return c.function(0);
 }
}

Dont l’exécution donne:

run:
 222
 999
 555
 777
 BUILD SUCCESSFUL (total time: 1 second)
Cet article, publié dans Langage, est tagué . Ajoutez ce permalien à vos favoris.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s