Výrazy Java Lambda (s príkladmi)

V tomto článku sa pomocou príkladov dozvieme o Java lambda výraze a použití výrazu lambda s funkčnými rozhraniami, všeobecným funkčným rozhraním a stream API.

Výraz lambda bol prvýkrát predstavený v prostredí Java 8. Jeho hlavným cieľom bolo zvýšiť výrazovú silu jazyka.

Ale predtým, ako sa pustíme do lambdas, musíme najskôr porozumieť funkčným rozhraniam.

Čo je funkčné rozhranie?

Ak rozhranie Java obsahuje jednu a iba jednu abstraktnú metódu, potom sa nazýva funkčné rozhranie. Táto jediná metóda špecifikuje zamýšľaný účel rozhrania.

Napríklad Runnablerozhranie z balíka java.lang; je funkčné rozhranie, pretože predstavuje iba jednu metódu, tj run().

Príklad 1: Definujte funkčné rozhranie v jave

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

Vo vyššie uvedenom príklade má rozhranie MyInterface iba jednu abstraktnú metódu getValue (). Ide teda o funkčné rozhranie.

Tu sme použili anotáciu @FunctionalInterface. Anotácia núti kompilátor Java, aby naznačil, že rozhranie je funkčné rozhranie. Preto neumožňuje mať viac ako jednu abstraktnú metódu. Nie je to však povinné.

V prostredí Java 7 sa funkčné rozhrania považovali za jednotlivé abstraktné metódy alebo typ SAM . SAM sa bežne implementovali s anonymnými triedami v prostredí Java 7.

Príklad 2: Implementácia SAM s anonymnými triedami v jave

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

Výstup :

 Práve som implementoval funkčné rozhranie Runnable.

Tu môžeme metóde odovzdať anonymnú triedu. To pomáha písať programy s menším počtom kódov v prostredí Java 7. Syntax však bola stále zložitá a bolo potrebných veľa ďalších riadkov kódu.

Java 8 rozšírila výkon SAMs o krok ďalej. Pretože vieme, že funkčné rozhranie má iba jednu metódu, nemalo by byť potrebné definovať názov tejto metódy, keď ju odovzdávame ako argument. Lambda výraz nám umožňuje presne to urobiť.

Úvod do výrazov lambda

Výraz lambda je v zásade anonymná alebo nepomenovaná metóda. Výraz lambda sa nevykonáva sám. Namiesto toho sa používa na implementáciu metódy definovanej funkčným rozhraním.

Ako definovať výraz lambda v Jave?

Tu je príklad, ako môžeme definovať výraz lambda v Jave.

 (parameter list) -> lambda body

Nový ->použitý operátor ( ) je známy ako operátor šípky alebo lambda. Syntax nemusí byť v tejto chvíli jasná. Poďme preskúmať niekoľko príkladov,

Predpokladajme, že máme takú metódu:

 double getPiValue() ( return 3.1415; )

Túto metódu môžeme napísať pomocou výrazu lambda ako:

 () -> 3.1415

Tu metóda nemá žiadne parametre. Preto ľavá strana operátora obsahuje prázdny parameter. Na pravej strane je telo lambda, ktoré určuje akciu výrazu lambda. V takom prípade vráti hodnotu 3.1415.

Druhy lambda karosérie

V jazyku Java je telo lambda dvoch typov.

1. Telo s jediným výrazom

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

Tento typ lambda tela je známy ako telo výrazu.

2. Telo, ktoré sa skladá z bloku kódu.

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

Tento typ lambda tela je známy ako blokové telo. Telo bloku umožňuje telu lambda obsahovať viac príkazov. Tieto vyhlásenia sú obsiahnuté vo vnútri zátvoriek a za zátvorky musíte pridať bodkočiarku.

Poznámka : Pre telo bloku môžete mať príkaz na návrat, ak telo vráti hodnotu. Telo výrazu však nevyžaduje príkaz na vrátenie.

Príklad 3: Lambda expresia

Poďme napísať program Java, ktorý vráti hodnotu Pi pomocou výrazu lambda.

Ako už bolo spomenuté, výraz lambda sa nevykonáva sám. Tvorí skôr implementáciu abstraktnej metódy definovanej funkčným rozhraním.

Najprv teda musíme definovať funkčné rozhranie.

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

Výstup :

 Hodnota Pi = 3,1415

Vo vyššie uvedenom príklade

  • Vytvorili sme funkčné rozhranie s názvom MyInterface. Obsahuje jednu abstraktnú metódu s názvomgetPiValue()
  • V triede Main sme deklarovali odkaz na MyInterface. Upozorňujeme, že môžeme deklarovať referenciu na rozhranie, ale nemôžeme vytvoriť inštanciu rozhrania. To znamená,
     // it will throw an error MyInterface ref = new myInterface(); // it is valid MyInterface ref;
  • Potom sme referencii priradili výraz lambda.
     ref = () -> 3.1415;
  • Nakoniec metódu zavoláme getPiValue()pomocou referenčného rozhrania. Kedy
     System.out.println("Value of Pi = " + ref.getPiValue());

Lambda výrazy s parametrami

Doteraz sme vytvorili výrazy lambda bez akýchkoľvek parametrov. Avšak podobne ako metódy, aj výrazy lambda môžu mať parametre. Napríklad,

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

Môžeme tiež definovať svoje vlastné výrazy na základe syntaxe, ktorú sme sa naučili vyššie. To nám umožňuje drasticky zmenšiť riadky kódu, ako sme videli vo vyššie uvedenom príklade.

Zaujímavé články...