Java Lambda izrazi (s primjerima)

U ovom ćemo članku uz primjere naučiti o Java lambda izrazu i uporabi lambda izraza s funkcionalnim sučeljima, generičkim funkcionalnim sučeljem i API-jem za strujanje.

Lambda izraz prvi je put predstavljen na Javi 8. Njegov glavni cilj je povećati izražajnu snagu jezika.

No, prije nego što se bavimo lambdama, prvo moramo razumjeti funkcionalna sučelja.

Što je funkcionalno sučelje?

Ako Java sučelje sadrži jednu i samo jednu apstraktnu metodu, tada se naziva funkcionalnim sučeljem. Ova samo jedna metoda određuje namjenu sučelja.

Na primjer, Runnablesučelje iz paketa java.lang; je funkcionalno sučelje jer predstavlja samo jednu metodu tj run().

Primjer 1: Definirajte funkcionalno sučelje u javi

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

U gornjem primjeru sučelje MyInterface ima samo jednu apstraktnu metodu getValue (). Dakle, to je funkcionalno sučelje.

Ovdje smo upotrijebili napomenu @FunctionalInterface. Bilješka prisiljava Java kompajler da naznači da je sučelje funkcionalno sučelje. Dakle, ne dopušta imati više od jedne apstraktne metode. Međutim, to ipak nije obvezno.

U Javi 7 funkcionalna sučelja smatrana su pojedinačnim apstraktnim metodama ili SAM tipom. SAM-ovi su se obično implementirali s Anonymous Classes u Javi 7.

Primjer 2: Implementirajte SAM s anonimnim klasama u javi

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

Izlaz :

 Upravo sam implementirao funkcionalno sučelje za pokretanje.

Ovdje možemo anonimnu klasu proslijediti metodi. To pomaže u pisanju programa s manje koda u Javi 7. Međutim, sintaksa je i dalje bila teška i bilo je potrebno puno dodatnih redaka koda.

Java 8 proširila je snagu SAM-a idući korak dalje. Budući da znamo da funkcionalno sučelje ima samo jednu metodu, ne bi trebalo biti potrebno definirati ime te metode prilikom prosljeđivanja kao argumenta. Lambda izraz omogućuje nam upravo to.

Uvod u lambda izraze

Lambda izraz je u osnovi anonimna ili neimenovana metoda. Lambda izraz ne izvršava se sam. Umjesto toga, koristi se za provedbu metode definirane funkcionalnim sučeljem.

Kako definirati lambda izraz u Javi?

Evo kako možemo definirati lambda izraz u Javi.

 (parameter list) -> lambda body

Novi operater ( ->) poznat je kao operator strelice ili lambda operator. Sintaksa trenutno možda nije jasna. Istražimo neke primjere,

Pretpostavimo da imamo metodu poput ove:

 double getPiValue() ( return 3.1415; )

Ovu metodu možemo napisati pomoću lambda izraza kao:

 () -> 3.1415

Ovdje metoda nema nikakve parametre. Stoga lijeva strana operatora uključuje prazan parametar. Desna strana je lambda tijelo koje specificira djelovanje lambda izraza. U ovom slučaju vraća vrijednost 3.1415.

Vrste Lambda tijela

U Javi je lambda tijelo dvije vrste.

1. Tijelo s jednim izrazom

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

Ova vrsta lambda tijela poznata je kao izraz tijela.

2. Tijelo koje se sastoji od bloka koda.

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

Ova vrsta lambda tijela poznata je kao blok tijelo. Tijelo bloka omogućuje lambda tijelu da uključi više izjava. Te su izjave zatvorene u zagradama, a nakon zagrada morate dodati tačku i zarez.

Napomena : Za tijelo bloka možete imati izraz return ako tijelo vraća vrijednost. Međutim, tijelo izraza ne zahtijeva povratnu izjavu.

Primjer 3: Lambda izraz

Napišimo Java program koji vraća vrijednost Pi pomoću lambda izraza.

Kao što je ranije spomenuto, lambda izraz se ne izvršava sam od sebe. Umjesto toga, čini provedbu apstraktne metode definirane funkcionalnim sučeljem.

Dakle, prvo moramo definirati funkcionalno sučelje.

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

Izlaz :

 Vrijednost Pi = 3,1415

U gornjem primjeru,

  • Stvorili smo funkcionalno sučelje nazvano MyInterface. Sadrži jednu apstraktnu metodu imenovanugetPiValue()
  • Unutar klase Main proglasili smo referencu na MyInterface. Imajte na umu da možemo proglasiti referencu sučelja, ali ne možemo instancirati sučelje. To je,
     // it will throw an error MyInterface ref = new myInterface(); // it is valid MyInterface ref;
  • Zatim smo referenci dodijelili lambda izraz.
     ref = () -> 3.1415;
  • Napokon, metodu pozivamo getPiValue()pomoću referentnog sučelja. Kada
     System.out.println("Value of Pi = " + ref.getPiValue());

Lambda izrazi s parametrima

Do sada smo stvorili lambda izraze bez ikakvih parametara. Međutim, slično metodama, i lambda izrazi mogu imati parametre. Na primjer,

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

Također možemo definirati vlastite izraze na temelju sintakse koju smo gore naučili. To nam omogućuje drastično smanjenje linija koda kao što smo vidjeli u gornjem primjeru.

Zanimljivi članci...