Јава Ламбда изрази (са примерима)

У овом чланку ћемо уз примере научити о Јава ламбда изразу и употреби ламбда израза са функционалним интерфејсима, генеричким функционалним интерфејсом и АПИ-јем тока.

Ламбда израз је први пут уведен на Јави 8. Његов главни циљ је повећање изражајне снаге језика.

Али, пре него што се позабавимо ламбдама, прво морамо да разумемо функционалне интерфејсе.

Шта је функционални интерфејс?

Ако Јава интерфејс садржи један и само један апстрактни метод, онда се назива функционалним интерфејсом. Ова само једна метода одређује намену интерфејса.

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

Пример 1: Дефинисање функционалног интерфејса у јави

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

У горњем примеру, интерфејс МиИнтерфаце има само једну апстрактну методу гетВалуе (). Дакле, то је функционалан интерфејс.

Овде смо користили напомену @FunctionalInterface. Напомена приморава Јава компајлер да укаже да је интерфејс функционалан интерфејс. Дакле, не дозвољава да постоји више од једне апстрактне методе. Међутим, то није обавезно.

У Јави 7 функционални интерфејси су сматрани појединачним апстрактним методама или САМ типом. САМ-ови су се обично примењивали са Анонимним класама у Јави 7.

Пример 2: Примените САМ са анонимним часовима у јави

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

Излаз :

 Управо сам имплементирао функционални интерфејс који се може покренути.

Овде можемо анонимну класу проследити методи. Ово помаже у писању програма са мање кодова у Јави 7. Међутим, синтакса је и даље била тешка и било је потребно пуно додатних редова кода.

Јава 8 је проширила снагу САМ-а идући корак даље. Будући да знамо да функционални интерфејс има само једну методу, не би требало бити потребно дефинирати име те методе када је прослеђујемо као аргумент. Ламбда израз нам омогућава управо то.

Увод у ламбда изразе

Ламбда израз је у основи анонимна или неименована метода. Ламбда израз се не извршава сам. Уместо тога, користи се за примену методе дефинисане функционалним интерфејсом.

Како дефинисати ламбда израз у Јави?

Ево како можемо да дефинишемо ламбда израз у Јави.

 (parameter list) -> lambda body

Нови оператер ( ->) познат је као оператор стрелице или ламбда оператор. Синтакса тренутно можда није јасна. Истражимо неке примере,

Претпоставимо да имамо метод попут овог:

 double getPiValue() ( return 3.1415; )

Ову методу можемо написати помоћу ламбда израза као:

 () -> 3.1415

Овде метода нема ниједан параметар. Дакле, лева страна оператора укључује празан параметар. Десна страна је ламбда тело које специфицира деловање ламбда израза. У овом случају враћа вредност 3.1415.

Врсте Ламбда тела

На Јави је ламбда тело две врсте.

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

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

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

2. Тело које се састоји од блока кода.

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

Ова врста ламбда тела позната је као тело блока. Тело блока омогућава ламбда телу да укључи више изјава. Ове изјаве су затворене у заградама, а након заграда морате додати тачку и зарез.

Напомена : За тело блока можете имати наредбу ретурн ако тело враћа вредност. Међутим, тело израза не захтева повратну изјаву.

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

Напишимо Јава програм који враћа вредност Пи користећи ламбда израз.

Као што је раније поменуто, ламбда израз се не извршава сам од себе. Уместо тога, он чини примену апстрактне методе дефинисане функционалним интерфејсом.

Дакле, прво морамо да дефинишемо функционални интерфејс.

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

Излаз :

 Вредност Пи = 3,1415

У горњем примеру,

  • Створили смо функционални интерфејс под називом МиИнтерфаце. Садржи једну апстрактну методу именовануgetPiValue()
  • Унутар класе Маин прогласили смо референцу на МиИнтерфаце. Имајте на уму да можемо прогласити референцу интерфејса, али не можемо инстанцирати интерфејс. То је,
     // 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.

Такође можемо дефинисати сопствене изразе на основу синтаксе коју смо претходно научили. Ово нам омогућава да драстично смањимо редове кода као што смо видели у горњем примеру.

Занимљиви Чланци...