Java Lambda-uttrykk (med eksempler)

I denne artikkelen vil vi lære om Java lambda-uttrykk og bruk av lambda-uttrykk med funksjonelle grensesnitt, generisk funksjonelt grensesnitt, og stream API ved hjelp av eksempler.

Lambda-uttrykket ble introdusert første gang i Java 8. Hovedmålet å øke språkets uttrykkskraft.

Men før vi går inn i lambdas, må vi først forstå funksjonelle grensesnitt.

Hva er funksjonelt grensesnitt?

Hvis et Java-grensesnitt inneholder en og bare en abstrakt metode, blir det betegnet som funksjonelt grensesnitt. Denne eneste metoden spesifiserer formålet med grensesnittet.

For eksempel Runnablegrensesnittet fra pakken java.lang; er en funksjonell grensesnitt fordi den utgjør bare en metode ie run().

Eksempel 1: Definer et funksjonelt grensesnitt i java

 import java.lang.FunctionalInterface; @FunctionalInterface public interface MyInterface( // the single abstract method double getValue(); )

I eksemplet ovenfor har grensesnittet MyInterface bare en abstrakt metode getValue (). Derfor er det et funksjonelt grensesnitt.

Her har vi brukt kommentaren @FunctionalInterface. Merknaden tvinger Java-kompilatoren til å indikere at grensesnittet er et funksjonelt grensesnitt. Tillater derfor ikke å ha mer enn en abstrakt metode. Det er imidlertid ikke obligatorisk.

I Java 7 ble funksjonelle grensesnitt betraktet som Single Abstract Methods eller SAM- type. SAM ble ofte implementert med anonyme klasser i Java 7.

Eksempel 2: Implementer SAM med anonyme klasser i java

 public class FunctionInterfaceTest ( public static void main(String() args) ( // anonymous class new Thread(new Runnable() ( @Override public void run() ( System.out.println("I just implemented the Runnable Functional Interface."); ) )).start(); ) )

Utgang :

 Jeg har nettopp implementert Runnable Functional Interface.

Her kan vi overføre en anonym klasse til en metode. Dette hjelper til med å skrive programmer med færre koder i Java 7. Syntaksen var likevel vanskelig, og det kreves mange ekstra kodelinjer.

Java 8 utvidet kraften til en SAM ved å gå et skritt videre. Siden vi vet at et funksjonelt grensesnitt bare har en metode, bør det ikke være behov for å definere navnet på den metoden når den sendes som et argument. Lambda-uttrykk lar oss gjøre akkurat det.

Introduksjon til lambdauttrykk

Lambda-uttrykk er i hovedsak en anonym eller ikke navngitt metode. Lambdauttrykket kjøres ikke av seg selv. I stedet brukes den til å implementere en metode definert av et funksjonelt grensesnitt.

Hvordan definere lambdauttrykk i Java?

Slik kan vi definere lambdauttrykk i Java.

 (parameter list) -> lambda body

Den nye operatøren ( ->) som brukes er kjent som en piloperator eller en lambda-operatør. Syntaksen er kanskje ikke klar for øyeblikket. La oss utforske noen eksempler,

Anta at vi har en metode som denne:

 double getPiValue() ( return 3.1415; )

Vi kan skrive denne metoden ved hjelp av lambdauttrykk som:

 () -> 3.1415

Her har ikke metoden noen parametere. Derfor inkluderer operatørens venstre side en tom parameter. Høyre side er lambdakroppen som spesifiserer virkningen av lambdauttrykket. I dette tilfellet returnerer den verdien 3.1415.

Typer Lambda Body

I Java er lambdakroppen av to typer.

1. En kropp med ett enkelt uttrykk

 () -> System.out.println("Lambdas are great");

Denne typen lambdakropp er kjent som uttrykkslegemet.

2. En kropp som består av en blokk med kode.

 () -> ( double pi = 3.1415; return pi; );

Denne typen lambdakropp er kjent som en blokklegeme. Blokklegemet gjør at lambdakroppen kan inkludere flere utsagn. Disse utsagnene er lukket inne i selene, og du må legge til et semikolon etter selene.

Merk : For blokkeringsdelen kan du ha en returoppgave hvis kroppen returnerer en verdi. Uttrykkningsorganet krever imidlertid ikke returoppgave.

Eksempel 3: Lambdauttrykk

La oss skrive et Java-program som returnerer verdien av Pi ved hjelp av lambda-uttrykket.

Som nevnt tidligere blir et lambdauttrykk ikke utført alene. Snarere danner det implementeringen av den abstrakte metoden definert av det funksjonelle grensesnittet.

Så vi må definere et funksjonelt grensesnitt først.

 import java.lang.FunctionalInterface; // this is functional interface @FunctionalInterface interface MyInterface( // abstract method double getPiValue(); ) public class Main ( public static void main( String() args ) ( // declare a reference to MyInterface MyInterface ref; // lambda expression ref = () -> 3.1415; System.out.println("Value of Pi = " + ref.getPiValue()); ) )

Utgang :

 Verdien av Pi = 3,1415

I eksemplet ovenfor,

  • Vi har opprettet et funksjonelt grensesnitt som heter MyInterface. Den inneholder en enkelt abstrakt metodegetPiValue()
  • Inne i hovedklassen har vi erklært en referanse til MyInterface. Merk at vi kan erklære en referanse til et grensesnitt, men vi kan ikke starte et grensesnitt. Det er,
     // it will throw an error MyInterface ref = new myInterface(); // it is valid MyInterface ref;
  • Vi tilordnet et lambdauttrykk til referansen.
     ref = () -> 3.1415;
  • Til slutt kaller vi metoden getPiValue()ved hjelp av referansegrensesnittet. Når
     System.out.println("Value of Pi = " + ref.getPiValue());

Lambda-uttrykk med parametere

Til nå har vi laget lambdauttrykk uten noen parametere. Imidlertid, i likhet med metoder, kan lambdauttrykk også ha parametere. For eksempel,

 (n) -> (n%2)==0

Here, the variable n inside the parenthesis is a parameter passed to the lambda expression. The lambda body takes the parameter and checks if it is even or odd.

Example 4: Using lambda expression with parameters

 @FunctionalInterface interface MyInterface ( // abstract method String reverse(String n); ) public class Main ( public static void main( String() args ) ( // declare a reference to MyInterface // assign a lambda expression to the reference MyInterface ref = (str) -> ( String result = ""; for (int i = str.length()-1; i>= 0 ; i--) result += str.charAt(i); return result; ); // call the method of the interface System.out.println("Lambda reversed = " + ref.reverse("Lambda")); ) )

Output:

 Lambda reversed = adbmaL

Generic Functional Interface

Till now we have used the functional interface that accepts only one type of value. For example,

 @FunctionalInterface interface MyInterface ( String reverseString(String n); )

The above functional interface only accepts String and returns String. However, we can make the functional interface generic, so that any data type is accepted. If you are not sure about generics, visit Java Generics.

Example 5: Generic Functional Interface and Lambda Expressions

 // GenericInterface.java @FunctionalInterface interface GenericInterface ( // generic method T func(T t); ) // GenericLambda.java public class Main ( public static void main( String() args ) ( // declare a reference to GenericInterface // the GenericInterface operates on String data // assign a lambda expression to it GenericInterface reverse = (str) -> ( String result = ""; for (int i = str.length()-1; i>= 0 ; i--) result += str.charAt(i); return result; ); System.out.println("Lambda reversed = " + reverse.func("Lambda")); // declare another reference to GenericInterface // the GenericInterface operates on Integer data // assign a lambda expression to it GenericInterface factorial = (n) -> ( int result = 1; for (int i = 1; i <= n; i++) result = i * result; return result; ); System.out.println("factorial of 5 = " + factorial.func(5)); ) )

Output:

 Lambda reversed = adbmaL factorial of 5 = 120

In the above example, we have created a generic functional interface named GenericInterface. It contains a generic method named func().

Here, inside the Main class,

  • GenericInterface reverse - creates a reference to the interface. The interface now operates on String type of data.
  • GenericInterface factorial - creates a reference to the interface. The interface, in this case, operates on the Integer type of data.

Lambda Expression and Stream API

The new java.util.stream package has been added to JDK8 which allows java developers to perform operations like search, filter, map, reduce, or manipulate collections like Lists.

For example, we have a stream of data (in our case a List of String) where each string is a combination of country name and place of the country. Now, we can process this stream of data and retrieve only the places from Nepal.

For this, we can perform bulk operations in the stream by the combination of Stream API and Lambda expression.

Example 6: Demonstration of using lambdas with the Stream API

 import java.util.ArrayList; import java.util.List; public class StreamMain ( // create an object of list using ArrayList static List places = new ArrayList(); // preparing our data public static List getPlaces()( // add places and country to the list places.add("Nepal, Kathmandu"); places.add("Nepal, Pokhara"); places.add("India, Delhi"); places.add("USA, New York"); places.add("Africa, Nigeria"); return places; ) public static void main( String() args ) ( List myPlaces = getPlaces(); System.out.println("Places from Nepal:"); // Filter places from Nepal myPlaces.stream() .filter((p) -> p.startsWith("Nepal")) .map((p) -> p.toUpperCase()) .sorted() .forEach((p) -> System.out.println(p)); ) )

Output:

 Places from Nepal: NEPAL, KATHMANDU NEPAL, POKHARA

In the above example, notice the statement,

 myPlaces.stream() .filter((p) -> p.startsWith("Nepal")) .map((p) -> p.toUpperCase()) .sorted() .forEach((p) -> System.out.println(p));

Here, we are using the methods like filter(), map() and forEach() of the Stream API. These methods can take a lambda expression as input.

Vi kan også definere våre egne uttrykk basert på syntaksen vi lærte ovenfor. Dette lar oss redusere kodelinjene drastisk som vi så i eksemplet ovenfor.

Interessante artikler...