Sådan begynder du at arbejde med Lambda Expressions i Java

Før Lambda-udtryksstøtte blev tilføjet af JDK 8, havde jeg kun brugt eksempler på dem på sprog som C # og C ++.

Når denne funktion blev tilføjet til Java, begyndte jeg at se nærmere på dem.

Tilføjelsen af ​​lambda-udtryk tilføjer syntakselementer, der øger Java's udtryksfulde styrke. I denne artikel vil jeg fokusere på grundlæggende begreber, du har brug for at blive fortrolig med, så du kan begynde at tilføje lambda-udtryk til din kode i dag.

Hurtig introduktion

Lambda-udtryk drager fordel af parallelle procesfunktioner i multi-core miljøer set med understøttelse af pipeline-operationer på data i Stream API.

Det er anonyme metoder (metoder uden navne), der bruges til at implementere en metode defineret af en funktionel grænseflade. Det er vigtigt at vide, hvad en funktionel grænseflade er, før du gør dine hænder beskidte med lambda-udtryk.

Funktionel grænseflade

En funktionel grænseflade er en grænseflade, der indeholder en og kun en abstrakt metode.

Hvis du tager et kig på definitionen af Java standarden Runnable grænseflade, vil du bemærke, hvordan den falder i definitionen af funktionel brugerflade, fordi det kun definerer en metode: run().

I nedenstående kodeeksempel er metoden computeNameimplicit abstrakt og er den eneste metode, der er defineret, hvilket gør MyName til en funktionel grænseflade.

interface MyName{ String computeName(String str); }

Piloperatøren

Lambda-udtryk introducerer den nye piloperator ->i Java. Det deler lambda-udtrykkene i to dele:

(n) -> n*n

Venstre side specificerer de parametre, der kræves af udtrykket, som også kan være tomme, hvis der ikke kræves nogen parametre.

Den højre side er lambda-kroppen, der specificerer lambda-udtryks handlinger. Det kan være nyttigt at tænke på denne operatør som ”bliver”. For eksempel bliver "n n * n" eller "n bliver n kvadrat".

Med tanke på funktionel grænseflade og piloperatører kan du sammensætte et enkelt lambda-udtryk:

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

Variablerne morningGreetingog eveningGreetinglinjerne 6 og 7 i eksemplet ovenfor henviser til MyGreetinginterface og definerer forskellige hilsenudtryk.

Når du skriver et lambda-udtryk, er det også muligt eksplicit at specificere typen af ​​parameter i udtrykket som dette:

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

Bloker Lambda-udtryk

Indtil videre har jeg dækket prøver af enkeltudtryk lambdas. Der er en anden type udtryk, der bruges, når koden i højre side af piloperatoren indeholder mere end en sætning kendt som block 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")); }

Generiske funktionelle grænseflader

Et lambda-udtryk kan ikke være generisk. Men den funktionelle grænseflade, der er forbundet med et lambda-udtryk, kan. Det er muligt at skrive en generisk grænseflade og håndtere forskellige returtyper som denne:

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

Lambda-udtryk som argumenter

En almindelig brug af lambdas er at videregive dem som argumenter.

De kan bruges i ethvert stykke kode, der giver en måltype. Jeg finder det spændende, da det giver mig mulighed for at videregive eksekverbar kode som argumenter til metoder.

For at videregive lambda-udtryk som parametre skal du bare sørge for, at den funktionelle grænsefladetype er kompatibel med den krævede parameter.

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

Disse begreber giver dig et godt fundament til at begynde at arbejde med lambda-udtryk. Se på din kode og se, hvor du kan øge den udtryksfulde kraft i Java.