Java Lambda Expressions (cu exemple)

În acest articol, vom învăța despre expresia lambda Java și utilizarea expresiei lambda cu interfețe funcționale, interfață funcțională generică și API de flux, cu ajutorul exemplelor.

Expresia lambda a fost introdusă prima dată în Java 8. Obiectivul său principal de a crește puterea expresivă a limbajului.

Dar, înainte de a intra în lambdas, trebuie mai întâi să înțelegem interfețele funcționale.

Ce este interfața funcțională?

Dacă o interfață Java conține o singură metodă abstractă, atunci aceasta este denumită interfață funcțională. Această singură metodă specifică scopul intenționat al interfeței.

De exemplu, Runnableinterfața din pachet java.lang; este o interfață funcțională deoarece constituie o singură metodă, adică run().

Exemplul 1: definiți o interfață funcțională în java

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

În exemplul de mai sus, interfața MyInterface are o singură metodă abstractă getValue (). Prin urmare, este o interfață funcțională.

Aici am folosit adnotarea @FunctionalInterface. Adnotarea forțează compilatorul Java să indice că interfața este o interfață funcțională. Prin urmare, nu permite să existe mai multe metode abstracte. Totuși, nu este obligatoriu.

În Java 7, interfețele funcționale au fost considerate metode abstracte unice sau de tip SAM . SAM-urile au fost implementate în mod obișnuit cu Anonymous Classes în Java 7.

Exemplul 2: Implementați SAM cu clase anonime în 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(); ) )

Ieșire :

 Tocmai am implementat interfața funcțională Runnable.

Aici, putem trece o clasă anonimă la o metodă. Acest lucru ajută la scrierea programelor cu mai puține coduri în Java 7. Cu toate acestea, sintaxa era încă dificilă și erau necesare multe linii de cod suplimentare.

Java 8 a extins puterea unui SAM mergând cu un pas mai departe. Din moment ce știm că o interfață funcțională are o singură metodă, nu ar trebui să fie necesar să se definească numele acelei metode atunci când este transmisă ca argument. Expresia Lambda ne permite să facem exact asta.

Introducere în expresiile lambda

Expresia Lambda este, în esență, o metodă anonimă sau nenumită. Expresia lambda nu se execută singură. În schimb, este folosit pentru a implementa o metodă definită de o interfață funcțională.

Cum se definește expresia lambda în Java?

Iată cum putem defini expresia lambda în Java.

 (parameter list) -> lambda body

Noul operator ( ->) utilizat este cunoscut sub numele de operator săgeată sau operator lambda. Sintaxa ar putea să nu fie clară în acest moment. Să explorăm câteva exemple,

Să presupunem că avem o metodă ca aceasta:

 double getPiValue() ( return 3.1415; )

Putem scrie această metodă folosind expresia lambda ca:

 () -> 3.1415

Aici, metoda nu are niciun parametru. Prin urmare, partea stângă a operatorului include un parametru gol. Partea dreaptă este corpul lambda care specifică acțiunea expresiei lambda. În acest caz, returnează valoarea 3.1415.

Tipuri de corp Lambda

În Java, corpul lambda este de două tipuri.

1. Un corp cu o singură expresie

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

Acest tip de corp lambda este cunoscut sub numele de corp de expresie.

2. Un corp care constă dintr-un bloc de cod.

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

Acest tip de corp lambda este cunoscut sub numele de corp bloc. Corpul blocului permite corpului lambda să includă mai multe instrucțiuni. Aceste afirmații sunt închise în interiorul parantezelor și trebuie să adăugați un punct și virgulă după paranteze.

Notă : Pentru corpul blocului, puteți avea o instrucțiune return dacă corpul returnează o valoare. Cu toate acestea, corpul expresiei nu necesită o declarație return.

Exemplul 3: Expresia Lambda

Să scriem un program Java care returnează valoarea lui Pi folosind expresia lambda.

După cum sa menționat mai devreme, o expresie lambda nu este executată singură. Mai degrabă, formează implementarea metodei abstracte definite de interfața funcțională.

So, we need to define a functional interface first.

 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:

 Value of Pi = 3.1415

In the above example,

  • We have created a functional interface named MyInterface. It contains a single abstract method named getPiValue()
  • Inside the Main class, we have declared a reference to MyInterface. Note that we can declare a reference of an interface but we cannot instantiate an interface. That is,
     // it will throw an error MyInterface ref = new myInterface(); // it is valid MyInterface ref;
  • We then assigned a lambda expression to the reference.
     ref = () -> 3.1415;
  • Finally, we call the method getPiValue() using the reference interface. When
     System.out.println("Value of Pi = " + ref.getPiValue());

Lambda Expressions with parameters

Till now we have created lambda expressions without any parameters. However, similar to methods, lambda expressions can also have parameters. For example,

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

De asemenea, ne putem defini propriile expresii pe baza sintaxei pe care am învățat-o mai sus. Acest lucru ne permite să reducem drastic liniile de cod așa cum am văzut în exemplul de mai sus.

Articole interesante...