Java Lambda -lausekkeet (esimerkkejä)

Tässä artikkelissa opitaan Java-lambda-ilmentymästä ja lambda-lausekkeen käytöstä toiminnallisilla rajapinnoilla, yleisellä toiminnallisella käyttöliittymällä ja stream-sovellusliittymällä esimerkkien avulla.

Lambda-ilmaisu otettiin ensimmäisen kerran käyttöön Java 8: ssa. Sen päätavoitteena on lisätä kielen ilmaisuvoimaa.

Mutta ennen pääsemistä lambdaan meidän on ensin ymmärrettävä toiminnalliset rajapinnat.

Mikä on toiminnallinen käyttöliittymä?

Jos Java-käyttöliittymä sisältää yhden ja vain yhden abstraktin menetelmän, sitä kutsutaan toiminnalliseksi käyttöliittymäksi. Tämä vain yksi menetelmä määrittelee käyttöliittymän tarkoituksen.

Esimerkiksi Runnablekäyttöliittymä paketista java.lang; on toiminnallinen rajapinta, koska se on vain yksi menetelmä eli run().

Esimerkki 1: Määritä Java-käyttöliittymä

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

Yllä olevassa esimerkissä MyInterface-rajapinnalla on vain yksi abstrakti menetelmä getValue (). Siksi se on toiminnallinen käyttöliittymä.

Tässä olemme käyttäneet merkintää @FunctionalInterface. Huomautus pakottaa Java-kääntäjän osoittamaan, että rajapinta on toiminnallinen rajapinta. Siksi ei salli useampaa kuin yhtä abstraktia menetelmää. Se ei kuitenkaan ole pakollinen.

Java 7: ssä toiminnallisia rajapintoja pidettiin Single Abstract Methods- tai SAM- tyyppisinä. SAM: t toteutettiin tavallisesti nimettömien luokkien kanssa Java 7: ssä.

Esimerkki 2: Ota SAM käyttöön anonyymien luokkien avulla javassa

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

Tuotos :

 Toteutin juuri Runnable Functional Interface -sovelluksen.

Täällä voimme siirtää nimettömän luokan menetelmälle. Tämä auttaa kirjoittamaan ohjelmia, joissa on vähemmän koodeja Java 7: ssä. Syntaksi oli kuitenkin edelleen vaikea ja tarvitaan paljon ylimääräisiä koodirivejä.

Java 8 laajensi SAMien tehoa siirtymällä askelta pidemmälle. Koska tiedämme, että toiminnallisella rajapinnalla on vain yksi menetelmä, ei pitäisi olla tarvetta määrittää menetelmän nimeä, kun se välitetään argumenttina. Lambda-ilmaisu antaa meille mahdollisuuden tehdä juuri niin.

Johdatus lambda-ilmaisuihin

Lambda-ilmaisu on pohjimmiltaan anonyymi tai nimeämätön menetelmä. Lambda-lauseke ei toteudu yksin. Sen sijaan sitä käytetään toiminnallisen rajapinnan määrittelemän menetelmän toteuttamiseen.

Kuinka määritellä lambda-lauseke Java-sovelluksessa?

Näin voimme määrittää lambda-lausekkeen Java-muodossa.

 (parameter list) -> lambda body

Uusi ->käytetty operaattori ( ) tunnetaan nuolioperaattorina tai lambdaoperaattorina. Syntaksi ei ehkä ole selkeä tällä hetkellä. Tutkitaan joitain esimerkkejä,

Oletetaan, että meillä on tällainen menetelmä:

 double getPiValue() ( return 3.1415; )

Voimme kirjoittaa tämän menetelmän käyttämällä lambda-lauseketta seuraavasti:

 () -> 3.1415

Tässä menetelmällä ei ole parametreja. Operaattorin vasemmalla puolella on siis tyhjä parametri. Oikea puoli on lambda-runko, joka määrittää lambda-ilmenteen toiminnan. Tässä tapauksessa se palauttaa arvon 3.1415.

Lambda-rungon tyypit

Jaavassa lambda-runko on kahden tyyppinen.

1. Runko, jolla on yksi lauseke

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

Tämäntyyppinen lambda-runko tunnetaan ekspressiokappaleena.

2. Runko, joka koostuu koodilohkosta.

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

Tämäntyyppinen lambda-runko tunnetaan lohkokappaleena. Lohkon runko antaa lambda-rungon sisällyttää useita lauseita. Nämä lauseet ovat sulkujen sisällä, ja sinun on lisättävä puolipiste kaksoispisteellä aaltosulkeiden jälkeen.

Huomaa : Lohkon rungolla voi olla palautuslauseke, jos body palauttaa arvon. Lauseke ei kuitenkaan vaadi palautuslauseketta.

Esimerkki 3: Lambda-ilmentymä

Kirjoitetaan Java-ohjelma, joka palauttaa Pi: n arvon käyttämällä lambda-lauseketta.

Kuten aiemmin mainittiin, lambda-lauseketta ei suoriteta yksin. Pikemminkin se muodostaa toiminnallisen rajapinnan määrittelemän abstraktin menetelmän toteutuksen.

Joten meidän on ensin määriteltävä toiminnallinen käyttöliittymä.

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

Tuotos :

 Pi: n arvo = 3,1415

Yllä olevassa esimerkissä

  • Olemme luoneet toiminnallisen käyttöliittymän nimeltä MyInterface. Se sisältää yhden abstraktin menetelmän nimeltägetPiValue()
  • Pääluokan sisällä olemme ilmoittaneet viittauksen MyInterfaceen. Huomaa, että voimme ilmoittaa käyttöliittymän viitteen, mutta emme voi luoda käyttöliittymää. Tuo on,
     // it will throw an error MyInterface ref = new myInterface(); // it is valid MyInterface ref;
  • Sitten osoitimme viitteeseen lambda-lausekkeen.
     ref = () -> 3.1415;
  • Lopuksi kutsutaan menetelmää getPiValue()vertailurajapinnan avulla. Kun
     System.out.println("Value of Pi = " + ref.getPiValue());

Lambda-lausekkeet parametreilla

Tähän asti olemme luoneet lambda-lausekkeita ilman parametreja. Menetelmien tapaan lambda-lausekkeilla voi kuitenkin olla myös parametreja. Esimerkiksi,

 (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.

Voimme myös määritellä omat ilmaisumme yllä oppimamme syntaksin perusteella. Tämä antaa meille mahdollisuuden vähentää koodirivejä rajusti, kuten näimme yllä olevassa esimerkissä.

Mielenkiintoisia artikkeleita...