Java Lambda-uttryck (med exempel)

I den här artikeln kommer vi att lära oss mer om Java lambdauttryck och användningen av lambdauttryck med funktionella gränssnitt, generiskt funktionellt gränssnitt och ström-API med hjälp av exempel.

Lambdauttrycket introducerades första gången i Java 8. Dess huvudsyfte är att öka språkets uttrycksfulla kraft.

Men innan vi går in i lambdas måste vi först förstå funktionella gränssnitt.

Vad är funktionellt gränssnitt?

Om ett Java-gränssnitt innehåller en och en abstrakt metod kallas det som funktionellt gränssnitt. Den här enda metoden anger gränssnittets avsedda syfte.

Till exempel Runnablegränssnittet från paketet java.lang; är ett funktionellt gränssnitt, eftersom den utgör endast en metod dvs run().

Exempel 1: Definiera ett funktionellt gränssnitt i java

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

I exemplet ovan har gränssnittet MyInterface bara en abstrakt metod getValue (). Därför är det ett funktionellt gränssnitt.

Här har vi använt anteckningen @FunctionalInterface. Anmärkningen tvingar Java-kompilatorn att indikera att gränssnittet är ett funktionellt gränssnitt. Tillåter därför inte att ha mer än en abstrakt metod. Det är dock inte obligatoriskt.

I Java 7 betraktades funktionella gränssnitt som Single Abstract Methods eller SAM- typ. SAM implementerades vanligtvis med anonyma klasser i Java 7.

Exempel 2: Implementera SAM med anonyma 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(); ) )

Utgång :

 Jag implementerade just Runnable Functional Interface.

Här kan vi skicka en anonym klass till en metod. Detta hjälper till att skriva program med färre koder i Java 7. Syntaxen var dock fortfarande svår och många extra kodrader krävdes.

Java 8 utökade kraften hos en SAM genom att gå ett steg längre. Eftersom vi vet att ett funktionellt gränssnitt bara har en metod, borde det inte vara nödvändigt att definiera namnet på den metoden när den skickas som ett argument. Lambdauttryck låter oss göra exakt det.

Introduktion till lambdauttryck

Lambdauttryck är i huvudsak en anonym eller namnlös metod. Lambdauttrycket körs inte på egen hand. Istället används den för att implementera en metod som definieras av ett funktionellt gränssnitt.

Hur definierar jag lambdauttryck i Java?

Så här kan vi definiera lambdauttryck i Java.

 (parameter list) -> lambda body

Den nya operatören ( ->) som används är känd som en piloperator eller en lambda-operatör. Syntaxen kanske inte är tydlig just nu. Låt oss utforska några exempel,

Antag att vi har en metod som den här:

 double getPiValue() ( return 3.1415; )

Vi kan skriva den här metoden med lambdauttryck som:

 () -> 3.1415

Här har metoden inga parametrar. Följaktligen innehåller operatörens vänstra sida en tom parameter. Den högra sidan är lambdakroppen som specificerar effekten av lambdauttrycket. I det här fallet returnerar det värdet 3.1415.

Typer av Lambda Body

I Java är lambdakroppen av två typer.

1. En kropp med ett enda uttryck

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

Denna typ av lambdakropp är känd som uttryckskroppen.

2. En kropp som består av ett kodblock.

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

Denna typ av lambdakropp är känd som en blockkropp. Blockkroppen gör det möjligt för lambdakroppen att inkludera flera uttalanden. Dessa påståenden är inneslutna inom hängslen och du måste lägga till en semikolon efter hängslen.

Obs! För blocket kan du ha ett returuttal om kroppen returnerar ett värde. Uttryckningsorganet kräver emellertid inte ett returuttalande.

Exempel 3: Lambdauttryck

Låt oss skriva ett Java-program som returnerar värdet på Pi med lambdauttrycket.

Som nämnts tidigare utförs inte ett lambdauttryck på egen hand. Snarare bildar det implementeringen av den abstrakta metoden som definieras av det funktionella gränssnittet.

Så vi måste först definiera ett funktionellt gränssnitt.

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

Utgång :

 Värdet på Pi = 3,1415

I exemplet ovan,

  • Vi har skapat ett funktionellt gränssnitt som heter MyInterface. Den innehåller en enda abstrakt metod som hetergetPiValue()
  • Inom huvudklassen har vi förklarat en hänvisning till MyInterface. Observera att vi kan förklara en referens för ett gränssnitt men vi kan inte starta ett gränssnitt. Det är,
     // it will throw an error MyInterface ref = new myInterface(); // it is valid MyInterface ref;
  • Vi tilldelade sedan ett lambdauttryck till referensen.
     ref = () -> 3.1415;
  • Slutligen kallar vi metoden med getPiValue()hjälp av referensgränssnittet. När
     System.out.println("Value of Pi = " + ref.getPiValue());

Lambdauttryck med parametrar

Hittills har vi skapat lambdauttryck utan några parametrar. I likhet med metoder kan lambdauttryck också ha parametrar. Till exempel,

 (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 också definiera våra egna uttryck baserat på syntaxen vi lärde oss ovan. Detta gör att vi kan minska kodraderna drastiskt som vi såg i exemplet ovan.

Intressanta artiklar...