English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Dans cet article, nous allons comprendre les expressions lambda Java par des exemples, ainsi que l'utilisation des interfaces fonctionnelles, des interfaces fonctionnelles génériques et de l'API Stream.
L'expression lambda est en Java 8Pour la première fois introduite. Son principal objectif est d'améliorer la capacité d'expression du langage.
Mais avant d'apprendre les lambdas, nous devons d'abord comprendre les interfaces fonctionnelles.
Si l'interface Java ne contient qu'une méthode abstraite, on l'appelle une interface fonctionnelle. C'est cette seule méthode qui spécifie l'utilisation prévue de l'interface.
例如,包java.lang中的Runnable接口;是一个功能接口,因为它只组成一个方法,即run()。
import java.lang.FunctionalInterface; @FunctionalInterface public interface MyInterface{ //单一抽象方法 double getValue(); }
在上面的示例中,接口MyInterface只有一个抽象方法getValue()。因此,它是一个功能接口。
在这里,我们使用了注解@FunctionalInterface。该注解会强制Java编译器指示该接口是功能接口。因此,不允许有多个抽象方法。但是,它不是强制性的。
在Java 7中,功能接口被视为单一抽象方法(SAM)类型。在Java 7中,SAM类型通常是通过匿名类实现的。
public class FunctionInterfaceTest { public static void main(String[] args) { //匿名类 new Thread(new Runnable() { @Override public void run() { System.out.println("我刚刚实现了Runnable功能接口。"); } }).start(); } }
Output:
我刚刚实现了Runnable功能接口。
在这里,我们可以将匿名类传递给方法。这有助于用Java 7编写代码更少的程序。但是,语法仍然很困难,需要大量的额外代码行。
Java 8进一步扩展了SAM的功能。由于我们知道功能接口只有一个方法,因此在将其作为参数传递时,无需定义该方法的名称。Lambda表达式使我们能够做到这一点。
Lambda表达式本质上是一个匿名或未命名的方法。lambda表达式不能单独执行。相反,它用于实现功能接口定义的方法。
这是我们如何在Java中定义lambda表达式。
(parameter list) -> lambda body
使用的新运算符(->)被称为箭头运算符或lambda运算符。让我们探索一些实例,
假设我们有一个这样的方法:
double getPiValue() { return 3.1415; }
Nous pouvons écrire cette méthode en utilisant une expression lambda comme suit:
(); -> 3.1415
Ici, cette méthode n'a aucun paramètre. Par conséquent, le côté gauche de l'opérateur inclut un paramètre vide. Le côté droit est le corps de lambda, qui spécifie l'opération de l'expression lambda. Dans ce cas, il renverra la valeur3.1415。
En Java, il y a deux types de corps de lambda.
1. Corps d'expression simple
(); -> System.out.println("Lambdas sont géniales");
Ce type de corps de lambda est appelé corps d'expression.
2. Un corps composé de blocs de code.
(); -> { double pi = 3.1415; return pi; };
Ce type de corps de lambda est appelé bloc. Le corps de bloc permet au corps de lambda de contenir plusieurs instructions. Ces instructions sont placées entre des parenthèses et vous devez ajouter un point-virgule à la fin des parenthèses.
Remarque: Pour le corps du bloc, vous devez toujours avoir une instruction return. Mais, un corps d'expression simple n'a pas besoin d'instruction return.
Écrivons un programme Java qui utilise une expression lambda pour renvoyer la valeur de Pi.
Comme mentionné précédemment, les expressions lambda ne s'exécutent pas séparément. Au lieu de cela, elles forment l'implémentation des méthodes abstraites définies par l'interface fonctionnelle.
Par conséquent, nous devons d'abord définir une interface fonctionnelle.
import java.lang.FunctionalInterface; //C'est une interface fonctionnelle @FunctionalInterface interface MyInterface{ // 抽象方法 double getPiValue(); } public class Main { public static void main(String[] args) { //声明对MyInterface的引用 MyInterface ref; // expression lambda ref = () -> 3.1415; System.out.println("Pi = "); + ref.getPiValue()); } }
Output:
Pi = 3.1415
Dans l'exemple précédent,
Nous avons créé une interface fonctionnelle nommée MyInterface. Elle contient une méthode abstraite nommée getPiValue().
À l'intérieur de la classe Main, nous déclarons une référence à MyInterface. Notez que nous pouvons déclarer une référence à l'interface, mais nous ne pouvons pas l'instancier. C'est parce que,
//Il va lancer une erreur MyInterface ref = new myInterface(); // C'est valable MyInterface ref;
Puis, nous avons assigné une expression lambda à la référence.
ref = () -> 3.1415;
Enfin, nous appelons la méthode getPiValue() via l'interface reference.
System.out.println("Pi = "); + ref.getPiValue());
Jusqu'à présent, nous avons créé des expressions lambda sans aucun paramètre. Mais, comme les méthodes, les expressions lambda peuvent également avoir des paramètres. Par exemple,
(n) -> (n%2)=0
在此,括号内的变量n是传递给lambda表达式的参数。Lambda主体接受参数并检查其是偶数还是奇数。
@FunctionalInterface interface MyInterface { //抽象方法 String reverse(String n); } public class Main { public static void main(String[] args) { //声明对MyInterface的引用 //将lambda表达式分配给引用 MyInterface ref = (str) -> { String result = ""; for (int i = str.length();-1; i >= 0 ; i--){ result += str.charAt(i); } return result; }; //调用接口的方法 System.out.println("Lambda reversed = "); + ref.reverse("Lambda")); } }
Output:
Lambda reversed = adbmaL
到目前为止,我们已经使用了仅接受一种类型的值的功能接口。例如,
@FunctionalInterface interface MyInterface { String reverseString(String n); }
上面的功能接口仅接受String并返回String。但是,我们可以使功能接口通用,以便接受任何数据类型。如果不熟悉泛型,请访问Java泛型。
// GenericInterface.java @FunctionalInterface interface GenericInterface<T> { // 泛型方法 T func(T t); } // GenericLambda.java public class Main { public static void main(String[] args) { //声明对GenericInterface的引用 // GenericInterface对String数据进行操作 //为其分配一个lambda表达式 GenericInterface<String> 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")); //声明对GenericInterface的另一个引用 // GenericInterface对整数数据进行操作 //为其分配一个lambda表达式 GenericInterface<Integer> factorial = (n) -> { int result = 1; for (int i = 1; i <= n; i++) result = i * result; return result; }; System.out.println("5Factorielle = " + factorial.func(5)); } }
Output:
Lambda reversed = adbmaL 5Factorielle = 120
Dans l'exemple précédent, nous avons créé une interface fonctionnelle générique nommée GenericInterface. Elle contient une méthode générique nommée func().
À l'intérieur de la classe :
GenericInterface<String> reverse - Créer une référence à cette interface. Maintenant, l'interface peut traiter des données de type String.
GenericInterface<Integer> factorial -Créer une référence à cette interface. Dans ce cas, l'interface opère sur des données de type Integer.
Nouveaujava.util.streamLe paquet a été ajouté au JDK8Java permet aux développeurs Java d'exécuter des opérations de recherche, de filtrage, de mappage, de réduction, etc., ou des opérations sur des listes et autres collections.
Par exemple, nous avons un flux de données (dans notre exemple, une liste de chaînes de caractères), où chaque chaîne de caractères est le nom d'un pays et/Combinaison des régions. Maintenant, nous pouvons traiter ce flux de données et ne récupérer que les emplacements du Népal.
Pour cela, nous pouvons combiner l'API Stream et les expressions Lambda pour effectuer des opérations en lots sur le flux.
import java.util.ArrayList; import java.util.List; public class StreamMain { //Utiliser ArrayList pour créer un objet liste static List<String> places = new ArrayList<>(); //Préparer nos données public static List getPlaces(){ //Ajouter des emplacements et des pays à la liste 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<String> myPlaces = getPlaces(); System.out.println("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, please note the following statements:
myPlaces.stream() .filter((p -> p.startsWith("Nepal")) .map((p -> p.toUpperCase()) .sorted() .forEach((p -> System.out.println(p));
Here, we use methods such as filter(), map(), and forEach() from the Stream API. These methods can take lambda expressions as input.
We can also define our own expressions based on the grammar we have learned above. As shown in the example above, this allows us to greatly reduce the number of lines of code.