Comment commencer à travailler avec les expressions Lambda en Java

Avant l'ajout de la prise en charge des expressions Lambda par JDK 8, je n'en avais utilisé que des exemples dans des langages tels que C # et C ++.

Une fois cette fonctionnalité ajoutée à Java, j'ai commencé à les examiner de plus près.

L'ajout d'expressions lambda ajoute des éléments de syntaxe qui augmentent la puissance expressive de Java. Dans cet article, je souhaite me concentrer sur les concepts de base avec lesquels vous devez vous familiariser afin que vous puissiez commencer à ajouter des expressions lambda à votre code dès aujourd'hui.

Introduction rapide

Les expressions Lambda tirent parti des capacités de processus parallèles des environnements multicœurs, comme le montre la prise en charge des opérations de pipeline sur les données dans l'API Stream.

Ce sont des méthodes anonymes (méthodes sans nom) utilisées pour implémenter une méthode définie par une interface fonctionnelle. Il est important de savoir ce qu'est une interface fonctionnelle avant de se salir les mains avec des expressions lambda.

Interface fonctionnelle

Une interface fonctionnelle est une interface qui contient une et une seule méthode abstraite.

Si vous jetez un oeil à la définition de l'interface standard Java Runnable, vous remarquerez comment il tombe dans la définition de l' interface fonctionnelle car elle définit une seule méthode: run().

Dans l'exemple de code ci-dessous, la méthode computeNameest implicitement abstraite et est la seule méthode définie, faisant de MyName une interface fonctionnelle.

interface MyName{ String computeName(String str); }

L'opérateur de flèche

Les expressions Lambda introduisent le nouvel opérateur de flèche ->dans Java. Il divise les expressions lambda en deux parties:

(n) -> n*n

Le côté gauche spécifie les paramètres requis par l'expression, qui peuvent également être vides si aucun paramètre n'est requis.

Le côté droit est le corps lambda qui spécifie les actions de l'expression lambda. Il peut être utile de considérer cet opérateur comme «devient». Par exemple, «n devient n * n» ou «n devient n au carré».

En gardant à l'esprit les concepts d'interface fonctionnelle et d'opérateur de flèche, vous pouvez créer une expression lambda simple:

interface NumericTest { boolean computeTest(int n); } public static void main(String args[]) { NumericTest isEven = (n) -> (n % 2) == 0; NumericTest isNegative = (n) -> (n < 0); // Output: false System.out.println(isEven.computeTest(5)); // Output: true System.out.println(isNegative.computeTest(-5)); }
interface MyGreeting { String processName(String str); } public static void main(String args[]) { MyGreeting morningGreeting = (str) -> "Good Morning " + str + "!"; MyGreeting eveningGreeting = (str) -> "Good Evening " + str + "!"; // Output: Good Morning Luis! System.out.println(morningGreeting.processName("Luis")); // Output: Good Evening Jessica! System.out.println(eveningGreeting.processName("Jessica")); }

Les variables morningGreetinget eveningGreeting, lignes 6 et 7 dans l'exemple ci-dessus, font référence à l' MyGreetinginterface et définissent différentes expressions de salutation.

Lors de l'écriture d'une expression lambda, il est également possible de spécifier explicitement le type du paramètre dans l'expression comme ceci:

MyGreeting morningGreeting = (String str) -> "Good Morning " + str + "!"; MyGreeting eveningGreeting = (String str) -> "Good Evening " + str + "!";

Bloquer les expressions Lambda

Jusqu'à présent, j'ai couvert des échantillons de lambdas à expression unique. Il existe un autre type d'expression utilisé lorsque le code sur le côté droit de l'opérateur de flèche contient plusieurs instructions appelées bloc lambdas :

interface MyString { String myStringFunction(String str); } public static void main (String args[]) { // Block lambda to reverse string MyString reverseStr = (str) -> { String result = ""; for(int i = str.length()-1; i >= 0; i--) result += str.charAt(i); return result; }; // Output: omeD adbmaL System.out.println(reverseStr.myStringFunction("Lambda Demo")); }

Interfaces fonctionnelles génériques

Une expression lambda ne peut pas être générique. Mais l'interface fonctionnelle associée à une expression lambda peut. Il est possible d'écrire une interface générique et de gérer différents types de retour comme ceci:

interface MyGeneric { T compute(T t); } public static void main(String args[]){ // String version of MyGenericInteface MyGeneric reverse = (str) -> { String result = ""; for(int i = str.length()-1; i >= 0; i--) result += str.charAt(i); return result; }; // Integer version of MyGeneric MyGeneric factorial = (Integer n) -> { int result = 1; for(int i=1; i <= n; i++) result = i * result; return result; }; // Output: omeD adbmaL System.out.println(reverse.compute("Lambda Demo")); // Output: 120 System.out.println(factorial.compute(5)); }

Expressions Lambda comme arguments

Une utilisation courante des lambdas est de les passer comme arguments.

Ils peuvent être utilisés dans n'importe quel morceau de code fournissant un type de cible. Je trouve cela passionnant, car cela me permet de passer du code exécutable comme arguments aux méthodes.

Pour passer des expressions lambda en tant que paramètres, assurez-vous simplement que le type d'interface fonctionnelle est compatible avec le paramètre requis.

interface MyString { String myStringFunction(String str); } public static String reverseStr(MyString reverse, String str){ return reverse.myStringFunction(str); } public static void main (String args[]) { // Block lambda to reverse string MyString reverse = (str) -> { String result = ""; for(int i = str.length()-1; i >= 0; i--) result += str.charAt(i); return result; }; // Output: omeD adbmaL System.out.println(reverseStr(reverse, "Lambda Demo")); }

Ces concepts vous donneront une bonne base pour commencer à travailler avec des expressions lambda. Jetez un œil à votre code et voyez où vous pouvez augmenter la puissance expressive de Java.