Java Lambda-Ausdrücke (mit Beispielen)

In diesem Artikel lernen wir anhand von Beispielen den Java-Lambda-Ausdruck und die Verwendung des Lambda-Ausdrucks mit Funktionsschnittstellen, der generischen Funktionsschnittstelle und der Stream-API kennen.

Der Lambda-Ausdruck wurde erstmals in Java 8 eingeführt. Sein Hauptziel ist es, die Ausdruckskraft der Sprache zu erhöhen.

Bevor wir uns jedoch mit Lambdas befassen, müssen wir zunächst die funktionalen Schnittstellen verstehen.

Was ist eine funktionale Schnittstelle?

Wenn eine Java-Schnittstelle nur eine abstrakte Methode enthält, wird sie als funktionale Schnittstelle bezeichnet. Diese einzige Methode gibt den beabsichtigten Zweck der Schnittstelle an.

Zum Beispiel die RunnableSchnittstelle aus Paket java.lang; ist eine funktionale Schnittstelle, da sie nur eine Methode darstellt, dh run().

Beispiel 1: Definieren Sie eine funktionale Schnittstelle in Java

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

Im obigen Beispiel hat die Schnittstelle MyInterface nur eine abstrakte Methode getValue (). Daher ist es eine funktionale Schnittstelle.

Hier haben wir die Anmerkung verwendet @FunctionalInterface. Die Annotation zwingt den Java-Compiler, anzugeben, dass die Schnittstelle eine funktionale Schnittstelle ist. Erlaubt daher nicht, mehr als eine abstrakte Methode zu haben. Es ist jedoch nicht obligatorisch.

In Java 7 wurden funktionale Schnittstellen als Single Abstract Methods oder SAM- Typ betrachtet. SAMs wurden üblicherweise mit anonymen Klassen in Java 7 implementiert.

Beispiel 2: Implementieren Sie SAM mit anonymen Klassen in 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(); ) )

Ausgabe :

 Ich habe gerade die Runnable Functional Interface implementiert.

Hier können wir eine anonyme Klasse an eine Methode übergeben. Dies hilft beim Schreiben von Programmen mit weniger Codes in Java 7. Die Syntax war jedoch immer noch schwierig und es waren viele zusätzliche Codezeilen erforderlich.

Java 8 erweiterte die Leistung eines SAMs um einen Schritt weiter. Da wir wissen, dass eine funktionale Schnittstelle nur eine Methode hat, sollte es nicht erforderlich sein, den Namen dieser Methode zu definieren, wenn Sie sie als Argument übergeben. Der Lambda-Ausdruck ermöglicht es uns, genau das zu tun.

Einführung in Lambda-Ausdrücke

Der Lambda-Ausdruck ist im Wesentlichen eine anonyme oder unbenannte Methode. Der Lambda-Ausdruck wird nicht alleine ausgeführt. Stattdessen wird eine Methode implementiert, die von einer funktionalen Schnittstelle definiert wird.

Wie definiere ich einen Lambda-Ausdruck in Java?

So können wir den Lambda-Ausdruck in Java definieren.

 (parameter list) -> lambda body

Der neu verwendete Operator ( ->) wird als Pfeiloperator oder Lambdaoperator bezeichnet. Die Syntax ist derzeit möglicherweise nicht klar. Lassen Sie uns einige Beispiele untersuchen,

Angenommen, wir haben eine Methode wie diese:

 double getPiValue() ( return 3.1415; )

Wir können diese Methode mit dem Lambda-Ausdruck schreiben als:

 () -> 3.1415

Hier hat die Methode keine Parameter. Daher enthält die linke Seite des Operators einen leeren Parameter. Die rechte Seite ist der Lambda-Körper, der die Wirkung des Lambda-Ausdrucks angibt. In diesem Fall wird der Wert 3.1415 zurückgegeben.

Arten von Lambda-Körper

In Java gibt es zwei Arten von Lambda-Körpern.

1. Ein Körper mit einem einzigen Ausdruck

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

Diese Art von Lambda-Körper ist als Ausdruckskörper bekannt.

2. Ein Körper, der aus einem Codeblock besteht.

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

Diese Art des Lambda-Körpers ist als Blockkörper bekannt. Der Blockkörper ermöglicht es dem Lambda-Körper, mehrere Anweisungen einzuschließen. Diese Anweisungen sind in geschweiften Klammern enthalten, und Sie müssen nach den geschweiften Klammern ein Semikolon einfügen.

Hinweis : Für den Blockkörper können Sie eine return-Anweisung haben, wenn der Körper einen Wert zurückgibt. Der Ausdruckskörper erfordert jedoch keine return-Anweisung.

Beispiel 3: Lambda-Expression

Schreiben wir ein Java-Programm, das den Wert von Pi mithilfe des Lambda-Ausdrucks zurückgibt.

Wie bereits erwähnt, wird ein Lambda-Ausdruck nicht alleine ausgeführt. Sie bildet vielmehr die Implementierung der durch die Funktionsschnittstelle definierten abstrakten Methode.

Wir müssen also zuerst eine funktionale Schnittstelle definieren.

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

Ausgabe :

 Wert von Pi = 3,1415

Im obigen Beispiel ist

  • Wir haben eine funktionale Schnittstelle namens MyInterface erstellt. Es enthält eine einzelne abstrakte Methode mit dem NamengetPiValue()
  • Innerhalb der Hauptklasse haben wir einen Verweis auf MyInterface deklariert. Beachten Sie, dass wir eine Referenz einer Schnittstelle deklarieren können, aber keine Schnittstelle instanziieren können. Das ist,
     // it will throw an error MyInterface ref = new myInterface(); // it is valid MyInterface ref;
  • Wir haben dann der Referenz einen Lambda-Ausdruck zugewiesen.
     ref = () -> 3.1415;
  • Schließlich rufen wir die Methode getPiValue()über die Referenzschnittstelle auf. Wann
     System.out.println("Value of Pi = " + ref.getPiValue());

Lambda-Ausdrücke mit Parametern

Bisher haben wir Lambda-Ausdrücke ohne Parameter erstellt. Ähnlich wie bei Methoden können Lambda-Ausdrücke jedoch auch Parameter haben. Beispielsweise,

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

Wir können auch unsere eigenen Ausdrücke basierend auf der oben erlernten Syntax definieren. Dies ermöglicht es uns, die Codezeilen drastisch zu reduzieren, wie wir im obigen Beispiel gesehen haben.

Interessante Beiträge...