1 Programmation fonctionnelle
En mathématiques, une fonction est un ensemble de plans de calcul avec des quantités d'entrée et de sortie, c'est-à-dire « ce qui est utilisé pour faire quelque chose ». Relativement parlant, l'orientation objet met trop l'accent sur "les choses doivent être faites sous la forme d'objets", tandis que la pensée fonctionnelle tente d'ignorer la syntaxe complexe de l'orientation objet - en mettant l'accent sur ce qu'il faut faire plutôt que sur la forme sous laquelle le faire.
1.1 Que faire, pas comment le faire
- Par exemple:
new Thread(new Runnable(){ @Override public void run(){ //TODO choses } }).start();
Concernant l’usage Runnable
des classes internes anonymes, plusieurs points peuvent être analysés :
- La classe
Thread
nécessiteRunnable
une interface comme paramètre et la méthode d'exécution abstraite est le noyau utilisé pour spécifier le contenu de la tâche du thread ; - Afin de spécifier le corps de la méthode run, nous devons créer une classe d'implémentation de
Runnable
l'interface ; - Afin d'éviter d'avoir à définir une classe
Runnable
d'implémentation , nous devons utiliser des classes internes anonymes ; - Dans la classe interne anonyme, nous devons remplacer et réécrire la méthode d'exécution abstraite, de sorte que le nom de la méthode, les paramètres de la méthode et la valeur de retour de la méthode doivent être réécrits et il ne doit y avoir aucune erreur ;
- En fait , seul le corps de la méthode run() est probablement la clé la plus importante du programme.
- Ce que nous voulons vraiment faire, c'est transmettre le code du corps de la méthode run à la classe Thread et l'exécuter.
pense:
Voulons-nous vraiment créer un objet de classe interne anonyme ? Non!
Il suffit de créer un objet pour ce faire.
1.2 Quelle est l'essence de la programmation fonctionnelle ?
Passer un morceau de code - c'est notre véritable objectif. La création d'objets n'est qu'une méthode qui doit être adoptée en raison de la syntaxe orientée objet. Alors, existe-t-il un moyen plus simple ?
Si nous ramenons notre attention du « comment faire » à l'essence du « quoi faire », nous constaterons que tant que l'objectif peut être mieux atteint, le processus et la forme ne sont pas réellement importants.
Un problème avec les classes internes anonymes est que même si l'implémentation de la classe interne anonyme est très simple, comme une interface qui ne contient qu'une méthode abstraite, la syntaxe de la classe interne anonyme semble toujours redondante.
Solution : Vous pouvez utiliser l'expression lambda prise en charge par JDK8. Cette expression n'est implémentée que pour une interface avec une méthode abstraite, et implémente la fonction d'interface sous la forme d'une expression concise en tant que paramètre de méthode.
new Thread(() -> System.out.println("Exécution de tâches multithread!")).start();
L'effet d'exécution de ce code est exactement le même que celui du moment, et il peut passer sous le niveau de compilation 1.8 ou supérieur. Cela se voit à la sémantique du code : nous démarrons un thread et le contenu de la tâche du thread est spécifié sous une forme plus concise.
Il n'y a plus les contraintes de « devoir créer des objets d'interface », et il n'y a plus le fardeau du « remplacement et de la réécriture de méthodes abstraites », c'est aussi simple que cela !
1.3Expression lambda
Format de syntaxe de base de l'expression lambda
Les flèches sont utilisées dans les instructions pour distinguer les listes de paramètres et les corps de méthode.
2Interface fonctionnelle
2.1 Est-il possible d'utiliser des lambdas au lieu de toutes les classes internes anonymes ?
Les expressions Lambda peuvent être utilisées à la place des classes internes anonymes lorsqu'il n'y a qu'une seule méthode abstraite dans l'interface. En effet, les expressions lambda sont implémentées sur la base d'interfaces fonctionnelles.
L'interface dite fonctionnelle fait référence à une interface avec une et une seule méthode abstraite. L'expression lambda est l'incarnation de la programmation fonctionnelle en Java. Ce n'est qu'en s'assurant que l'interface a une et une seule méthode abstraite que l'expression lambda peut déduire avec succès l'interface implémentée. .méthode dans.
2.2 Définition
Dans JDK8, l'interface marquée de l'annotation @FunctionalInterface est une interface fonctionnelle, et il n'y a qu'une seule méthode abstraite à l'intérieur de l'interface fonctionnelle.
Jetons un coup d'œil au code source dans l'interface Runnable :
Remarque : L'annotation @FunctionalInterface marque explicitement uniquement l'interface comme une interface fonctionnelle et oblige l'éditeur à effectuer des contrôles plus stricts pour garantir que l'interface est une interface fonctionnelle.
Quelques interfaces fonctionnelles qui existaient avant JDK8 :
- java.lang.Runnable
- java.util.Comparateur
- java.io.FileFilter
- java.lang.Reflect.InvocationHandler
Interface fonctionnelle ajoutée dans JDK8
Le package java.util.function contient de nombreuses classes pour prendre en charge la programmation fonctionnelle en Java.
2.3 Simplification des expressions Lambda
La méthode d'écriture omise de l'expression lambda (simplification supplémentaire basée sur l'expression lambda)
1. Si le code du corps de la méthode de l'expression lambda ne contient qu'une seule ligne de code, vous pouvez omettre les accolades et le point-virgule !
2. Si le code du corps de la méthode de l'expression lambda n'a qu'une seule ligne de code et si cette ligne de code est une instruction return, le return doit être omis et le point-virgule doit être omis.
3. Le type de paramètre peut être omis.
4. S'il n'y a qu'un seul paramètre, le () en dehors du paramètre peut également être omis.
En plus des règles de simplification ci-dessus, les expressions lambda peuvent être encore simplifiées à l'aide de « références de méthode ».
public class TestOutter { public static void main(String[] args) { //Méthode d'écriture de fonction anonyme new Thread(new Runnable() { @Override public void run() { System.out.println("Le thread 1 est démarré !" ) ; } }).start(); //méthode d'écriture lambda new Thread(() -> {System.out.println("Thread 2 démarré!");}.start(); } }
3 référence de méthode
Remarque : Lorsque le corps de l'expression lambda n'a qu'une seule instruction, le programme peut non seulement omettre les accolades contenant le corps, mais également référencer des méthodes et des constructeurs (c'est-à-dire des méthodes de construction) via la syntaxe anglaise à double deux-points "::" format.
Fonction : Il peut simplifier davantage l'écriture des expressions lambda. Son essence est de référencer directement les méthodes existantes dans la partie principale de l'expression lambda. La principale différence est la référence aux méthodes ordinaires et aux méthodes du constructeur.
3.1 Le nom de la classe fait référence à une méthode statique
Définition : Le nom de la classe fait référence à la méthode statique, qui est la référence à la méthode statique via le nom de la classe. La classe peut être une classe spéciale fournie avec Java ou une classe ordinaire personnalisée.
Des exemples de citations sont les suivants :
//Définir l'interface fonctionnelle @FunctionalInterface interface Calcable{ int calc(int num); } //Définir une classe et définir une méthode statique dans la classe class Math{ public static int abs(int num){ return num > 0 ? num : -num; } } exemple de classe publique { private static void printAbs(int num, Calcable calcable){ System.out.println(calcable.calc(num)); } public static void main(String[] args) { //1 , utilisez la classe interne anonyme printAbs(-8, new Calcable() { @Override public int calc(int num) { return Math.abs(num); } }); //2. Utiliser l'expression lambda printAbs(-8, (num) -> {return Math.abs(num);}); //3. Simplifier l'expression lambda printAbs(-9, num -> Math.abs(num)); //4. Utiliser références de méthodes pour simplifier les expressions lambda printAbs(-7, Math::abs); } }
3.2 Méthode de référence du nom d'objet
Définition : La méthode de référence de nom d'objet fait référence à la référence à sa méthode via le nom de l'objet instancié.
Des exemples de citations sont les suivants :
//Définir l'interface fonctionnelle @FunctionalInterface interface Utils{ String calc(String str); } //Définir une classe et définir une méthode commune dans la classe class UpperUtil{ public String toUpper(String str){ return str.toUpperCase(); } } public class Exemple2 { private static void printUpper(String ori, Utils u){ System.out.println(u.calc(ori)); } public static void main(String[] args) { UpperUtil upper = new UpperUtil() ; //1. Utiliser la classe interne anonyme printUpper("abc", new Utils() { @Override public String calc(String ori) { return upper.toUpper(ori); } }); //2. Utilisez l'expression lambda printUpper("bcd", (ori) -> {return upper.toUpper(ori);}); // 3. Simplifiez l'expression lambda printUpper("cde", ori -> upper. toUpper( ori)); //4. Utilisez des références de méthode pour simplifier les expressions lambda printUpper("def", upper::toUpper); } }
3.3 Méthode de référence du constructeur
Définition : fait référence à une référence au constructeur fourni avec la classe.
Des exemples de citations sont les suivants :
//Définir l'interface fonctionnelle @FunctionalInterface interface PersonBuilder{ Person buildPerson(String name); } //Définir une classe, définir un constructeur et des méthodes communes dans la classe class Person{ private String name; public Person(String name){ this. name = nom; } public String getName(){ return name; } } public class Exemple3 { private static void printName(String name, PersonBuilder buildPerson){ System.out.println(buildPerson.buildPerson(name).getName()); } public static void main(String[] args) { //1. Utilisez l'expression lambda printName("李思", (String name) -> {return new Person(name);}); //2. Utilisez la méthode de référence du constructeur printName("Zhang San", Person::new); } }
3.4 Les noms de classe font référence à des méthodes courantes
Définition : fait référence à une référence à une méthode commune d'une classe commune via son nom de classe.
Des exemples de citations sont les suivants :
//Définir une interface fonctionnelle @FunctionalInterface interface Printable{ void print(StringUtils su, String str); } //Définir une classe et une méthode class StringUtils{ public void printUppercase(String str){ System.out.println(str.toUpperCase( ) ); } } public class Exemple4 { private static void printUpper(StringUtils su, String str, Printable printable){ printable.print(su, str); } public static void main(String[] args) { //1. Utiliser Anonyme classe interne printUpper(new StringUtils(), "abc", new Printable() { @Override public void print(StringUtils su, String str) { su.printUppercase(str); } }); //2. Utilisez l'expression lambda printUpper(new StringUtils(), "bcd", (Object, t) -> Object.printUppercase(t)); // 3. Utilisez la référence de méthode printUpper(new StringUtils(), "def" , StringUtils::printUppercase); } }