Java Lambda-udtryk (med eksempler)

I denne artikel lærer vi om Java lambda-udtryk og brugen af ​​lambda-udtryk med funktionelle grænseflader, generisk funktionel grænseflade og stream API ved hjælp af eksempler.

Lambda-udtrykket blev introduceret første gang i Java 8. Dets hovedmål er at øge sprogets udtryksfulde kraft.

Men inden vi går ind i lambdas, skal vi først forstå funktionelle grænseflader.

Hvad er funktionelt interface?

Hvis en Java-grænseflade indeholder en og kun en abstrakt metode, betegnes den som funktionel grænseflade. Denne eneste metode specificerer det tilsigtede formål med grænsefladen.

For eksempel Runnablegrænsefladen fra pakke java.lang; er en funktionel brugerflade, fordi det udgør kun en metode dvs run().

Eksempel 1: Definer en funktionel grænseflade i java

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

I ovenstående eksempel har grænsefladen MyInterface kun en abstrakt metode getValue (). Derfor er det en funktionel grænseflade.

Her har vi brugt kommentaren @FunctionalInterface. Annotationen tvinger Java-kompilatoren til at indikere, at grænsefladen er en funktionel grænseflade. Tillader derfor ikke at have mere end en abstrakt metode. Det er dog ikke obligatorisk.

I Java 7 blev funktionelle grænseflader betragtet som Single Abstract Methods eller SAM- type. SAM'er blev almindeligt implementeret med anonyme klasser i Java 7.

Eksempel 2: Implementér 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(); ) )

Output :

 Jeg har lige implementeret Runnable Functional Interface.

Her kan vi overføre en anonym klasse til en metode. Dette hjælper med at skrive programmer med færre koder i Java 7. Syntaksen var dog stadig vanskelig, og der kræves mange ekstra kodelinjer.

Java 8 udvidede kraften i en SAM ved at gå et skridt videre. Da vi ved, at en funktionel grænseflade kun har en metode, skal der ikke være behov for at definere navnet på den metode, når den sendes som et argument. Lambda-udtryk giver os mulighed for at gøre netop det.

Introduktion til lambda-udtryk

Lambda-udtryk er i det væsentlige en anonym eller unavngiven metode. Lambda-udtrykket udføres ikke alene. I stedet bruges den til at implementere en metode defineret af en funktionel grænseflade.

Hvordan defineres lambda-udtryk i Java?

Her er hvordan vi kan definere lambda-udtryk i Java.

 (parameter list) -> lambda body

Den nye operatør ( ->), der er brugt, er kendt som en piloperator eller en lambda-operatør. Syntaksen er muligvis ikke klar i øjeblikket. Lad os undersøge nogle eksempler,

Antag, vi har en metode som denne:

 double getPiValue() ( return 3.1415; )

Vi kan skrive denne metode ved hjælp af lambda-udtryk som:

 () -> 3.1415

Her har metoden ingen parametre. Derfor inkluderer operatørens venstre side en tom parameter. Den højre side er lambdakroppen, der specificerer virkningen af ​​lambda-udtrykket. I dette tilfælde returnerer den værdien 3.1415.

Typer af Lambda Body

I Java er lambdakroppen af ​​to typer.

1. En krop med et enkelt udtryk

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

Denne type lambda-krop er kendt som udtrykslegemet.

2. Et organ, der består af en blok kode.

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

Denne type lambda-krop er kendt som en bloklegeme. Bloklegemet tillader lambdakroppen at omfatte flere udsagn. Disse udsagn er lukket inde i selerne, og du skal tilføje en semikolon efter selerne.

Bemærk : For blokteksten kan du have en returerklæring, hvis kroppen returnerer en værdi. Imidlertid kræver udtryksorganet ikke en returerklæring.

Eksempel 3: Lambdaekspression

Lad os skrive et Java-program, der returnerer værdien af ​​Pi ved hjælp af lambda-udtrykket.

Som nævnt tidligere udføres et lambda-udtryk ikke alene. Det danner snarere implementeringen af ​​den abstrakte metode, der er defineret af den funktionelle grænseflade.

Så vi skal først definere en funktionel grænseflade.

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

Output :

 Værdien af ​​Pi = 3,1415

I ovenstående eksempel

  • Vi har oprettet en funktionel grænseflade ved navn MyInterface. Den indeholder en enkelt abstrakt metode navngivetgetPiValue()
  • Inde i hovedklassen har vi erklæret en henvisning til MyInterface. Bemærk, at vi kan erklære en reference for en grænseflade, men vi kan ikke instantiere en grænseflade. Det er,
     // it will throw an error MyInterface ref = new myInterface(); // it is valid MyInterface ref;
  • Vi tildelte derefter et lambda-udtryk til referencen.
     ref = () -> 3.1415;
  • Endelig kalder vi metoden getPiValue()ved hjælp af referencegrænsefladen. Hvornår
     System.out.println("Value of Pi = " + ref.getPiValue());

Lambda-udtryk med parametre

Indtil nu har vi oprettet lambda-udtryk uden nogen parametre. I lighed med metoder kan lambda-udtryk imidlertid også have parametre. 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 vores egne udtryk baseret på den syntaks, vi har lært ovenfor. Dette giver os mulighed for at reducere kodelinjerne drastisk, som vi så i eksemplet ovenfor.

Interessante artikler...