Java Lambda изрази (с примери)

В тази статия ще научим за ламбда израза на Java и използването на ламбда израз с функционални интерфейси, общ функционален интерфейс и API на потока с помощта на примери.

Ламбда изразът е въведен за първи път в Java 8. Основната му цел е да увеличи изразителната сила на езика.

Но преди да влезем в ламбда, първо трябва да разберем функционалните интерфейси.

Какво е функционален интерфейс?

Ако интерфейсът на Java съдържа един и само един абстрактен метод, той се нарича функционален интерфейс. Този само един метод определя предназначението на интерфейса.

Например Runnableинтерфейсът от пакета java.lang; е функционална интерфейс защото тя представлява само един метод, т.е. run().

Пример 1: Определете функционален интерфейс в java

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

В горния пример интерфейсът MyInterface има само един абстрактен метод getValue (). Следователно, това е функционален интерфейс.

Тук използвахме анотацията @FunctionalInterface. Анотацията принуждава Java компилатора да посочи, че интерфейсът е функционален интерфейс. Следователно, не позволява да има повече от един абстрактен метод. Това обаче не е задължително.

В Java 7 функционалните интерфейси се разглеждат като единични абстрактни методи или тип SAM . SAMs често се прилагат с анонимни класове в Java 7.

Пример 2: Внедрете SAM с анонимни класове в 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(); ) )

Изход :

 Току-що внедрих функционалния интерфейс Runnable.

Тук можем да предадем анонимен клас на метод. Това помага да се пишат програми с по-малко кодове в Java 7. Синтаксисът обаче все още е труден и се изискват много допълнителни редове код.

Java 8 разшири мощността на SAM, като направи крачка напред. Тъй като знаем, че функционалният интерфейс има само един метод, не би трябвало да се дефинира името на този метод, когато се предава като аргумент. Ламбда изразът ни позволява да направим точно това.

Въведение в ламбда изразите

Ламбда изразът е по същество анонимен или неназован метод. Ламбда изразът не се изпълнява сам. Вместо това се използва за реализиране на метод, дефиниран от функционален интерфейс.

Как да дефинирам ламбда израз в Java?

Ето как можем да дефинираме ламбда израза в Java.

 (parameter list) -> lambda body

Използваният нов оператор ( ->) е известен като оператор със стрелка или ламбда оператор. В момента синтаксисът може да не е ясен. Нека разгледаме някои примери,

Да предположим, че имаме метод като този:

 double getPiValue() ( return 3.1415; )

Можем да напишем този метод, използвайки ламбда израз като:

 () -> 3.1415

Тук методът няма никакви параметри. Следователно лявата страна на оператора включва празен параметър. Дясната страна е ламбда тялото, което определя действието на ламбда израза. В този случай той връща стойността 3.1415.

Видове ламбда тяло

В Java ламбда тялото е от два вида.

1. Тяло с един израз

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

Този тип ламбда тяло е известно като израз на тялото.

2. Тяло, което се състои от блок с код.

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

Този тип ламбда тяло е известно като блоково тяло. Тялото на блока позволява на ламбда тялото да включва множество изрази. Тези изявления са затворени в скобите и трябва да добавите точка и запетая след скобите.

Забележка : За тялото на блока можете да имате оператор return, ако тялото връща стойност. Тялото на израза обаче не изисква оператор return.

Пример 3: Ламбда изразяване

Нека напишем Java програма, която връща стойността на Pi, използвайки ламбда израза.

Както бе споменато по-рано, ламбда израз не се изпълнява сам. По-скоро той формира изпълнението на абстрактния метод, дефиниран от функционалния интерфейс.

И така, първо трябва да дефинираме функционален интерфейс.

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

Изход :

 Стойност на Pi = 3.1415

В горния пример,

  • Създадохме функционален интерфейс, наречен MyInterface. Той съдържа един абстрактен метод с имеgetPiValue()
  • В класа Main сме декларирали препратка към MyInterface. Имайте предвид, че можем да декларираме препратка към интерфейс, но не можем да създадем екземпляр на интерфейс. Това е,
     // it will throw an error MyInterface ref = new myInterface(); // it is valid MyInterface ref;
  • След това присвоихме ламбда израз на препратката.
     ref = () -> 3.1415;
  • И накрая, извикваме метода, getPiValue()използвайки референтния интерфейс. Кога
     System.out.println("Value of Pi = " + ref.getPiValue());

Ламбда изрази с параметри

Досега създадохме ламбда изрази без никакви параметри. Подобно на методите обаче, ламбда изразите също могат да имат параметри. Например,

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

Също така можем да дефинираме собствените си изрази въз основа на синтаксиса, който научихме по-горе. Това ни позволява да намалим драстично редовете на кода, както видяхме в горния пример.

Интересни статии...