La première fois, j'ai été exposé aux expressions de Lambda, c'était dans TypeScript (le sur-ensemble de JavaScript), et c'était pour faire la méthode de TypeScript en dehors de cette méthode plutôt que dans cette méthode. Après l'avoir utilisé, j'ai soudainement réalisé que Lambda n'est pas une nouvelle fonctionnalité lourde de JDK8? J'ai donc senti que j'avais vérifié les informations pertinentes et l'avais enregistrée:
1. Paramétrage du comportement
En bref, le paramétrage du comportement signifie que le corps de la fonction ne contient que du code général de type modèle, tandis qu'une logique qui change avec le scénario commercial est transmise dans la fonction sous forme de paramètres. L'utilisation du paramétrage du comportement peut rendre le programme plus général pour faire face aux besoins des changements fréquents.
Envisagez un scénario d'entreprise, en supposant que nous devons filtrer Apple via un programme, nous définissons d'abord une entité Apple:
classe publique Apple {/ ** numéro * / ID long privé; / ** couleur * / couleur privée couleur; / ** poids * / poids de flotteur privé; / ** Origin * / Origine de chaîne privée; Apple public () {} public Apple (Long ID, couleur, poids de flottante, thordion) {this.id = id; this.color = couleur; this.weight = this.origin = origin;} // omit Getter et Setter};La demande initiale des utilisateurs peut être simplement de filtrer les pommes vertes via le programme, afin que nous puissions les implémenter rapidement via le programme:
LISTE STATIQUE PUBLIQUE <Apple> FilterGreenApples (List <Plate> Apples) {List <Apple> FilterApples = New ArrayList <> (); For (Final Apple Apple: Apples) {if (Color.green.equals (Apple.getColor ())) {filterApples.Add (Apple);}} Retour FilterApples;}Ce code est simple et rien de la peine d'être dit. Mais lorsque l'utilisateur a besoin de devenir vert, il semble que la modification du code soit simple, ce n'est rien de plus que de modifier le vert de la condition de jugement en rouge. Mais nous devons considérer un autre problème. Si les conditions changeantes changent fréquemment, cela est fait? S'il s'agit juste d'un changement de couleur, nous pouvons directement laisser l'utilisateur passer dans les conditions de jugement des couleurs, et les paramètres de la méthode de jugement modifier "l'ensemble à juger et la couleur à filtrer". Mais que se passe-t-il si l'utilisateur juge non seulement la couleur, mais veut également juger le poids, la taille, etc.? Pensez-vous que nous pouvons simplement ajouter différents paramètres pour compléter le jugement? Mais est-il vraiment bon de passer des paramètres comme celui-ci? S'il y a de plus en plus de conditions de filtrage et que le mode de combinaison devient de plus en plus complexe, devons-nous considérer toutes les situations et avoir des stratégies d'adaptation correspondantes pour chaque situation? Pour le moment, nous pouvons paramétrer le comportement, extraire les conditions de filtrage et les transmettre en tant que paramètres. Pour le moment, nous pouvons encapsuler une interface de jugement:
Interface publique Applefilter {/ *** Filter Résumé ** @param Apple * @ return * / booléen accepte (Apple Apple);} / *** Filtres d'encapsules dans l'interface ** @param pommes * @param filtre * @ return * / public static List <Pomme> FilterApplesByAppleFilter (List <Apples, pneum ArrayList <> (); pour (Final Apple Apple: pommes) {if (filter.accept (Apple)) {filterApples.add (Apple);}} return FilterApples;}Après l'abstraction de comportement ci-dessus, nous pouvons définir des conditions de filtre dans l'appel spécifique et passer les conditions sous forme de paramètres dans la méthode. Pour le moment, nous utilisons la méthode de la classe intérieure anonyme:
public static void main (String [] args) {list <Apple> pommes = new ArrayList <> (); // Filter Apple List <Apple> FilterApples = FilterApplesByAppleFilter (Apples, New AppleFilter () {@OverRidepublic Boolean Accept (Apple Apple) {// Filter Red Apples avec son poids que 100G Apple.getweight ()> 100;}});}Cette conception est souvent utilisée dans JDK, comme java.util ..comparator, java.util.concurrent. callable, etc. Lorsque vous utilisez ce type d'interface, nous pouvons utiliser des classes anonymes pour spécifier la logique d'exécution spécifique de la fonction dans les lieux d'appel spécifiques. Cependant, à partir du bloc de code ci-dessus, bien qu'il soit très geek, il n'est pas assez concis. Dans Java8, nous pouvons le simplifier via Lambda:
// Filter Apple List <Plate> FilterApples = FilterApplesByAppleFilter (Apples, (Apple Apple) -> Color.red.equals (Apple.getColor ()) && Apple.getweight ()> = 100); // () -> xxx () est les paramètres de la méthode, et xxx est l'implémentation de la méthode
2. Définition d'expression de lambda
Nous pouvons définir une expression de lambda comme une fonction anonyme concise et passable. Tout d'abord, nous devons indiquer clairement que l'expression de Lambda est essentiellement une fonction. Bien qu'il n'appartient pas à une classe spécifique, il a une liste de paramètres, un corps de fonction, un type de retour et la possibilité de lancer des exceptions; Deuxièmement, il est anonyme, et l'expression de lambda n'a pas de nom de fonction spécifique; L'expression de Lambda peut être transmise comme des paramètres, simplifiant ainsi considérablement l'écriture du code. La définition du format est la suivante:
Format 1: Liste des paramètres -> Expression
Format 2: Liste des paramètres -> {Collection d'expression}
Il convient de noter que l'expression de lambda implique le mot clé de retour, donc dans une seule expression, nous n'avons pas besoin d'écrire explicitement le mot-clé de retour, mais lorsque l'expression est une collection d'instructions, nous devons ajouter explicitement et enfermer plusieurs expressions avec des accolades bouclées {}. Voyons quelques exemples ci-dessous:
// Renvoie la longueur de la chaîne donnée, return implicitement instruction (String S) -> s.length () // renvoie toujours la méthode non argumentée () () -> 42 // contient plusieurs lignes d'expression, enfermées en accolades bouclées (int x, int y) -> {int z = x * y; return x + z;}3. Utilisez des expressions lambda basées sur des interfaces fonctionnelles
L'utilisation d'expressions lambda nécessite l'aide d'interfaces fonctionnelles, ce qui signifie que ce n'est que lorsque l'interface fonctionnelle apparaît peut les simplifier avec des expressions de lambda.
Interface fonctionnelle personnalisée:
Les interfaces fonctionnelles sont définies comme des interfaces qui n'ont qu'une seule méthode abstraite. L'amélioration de la définition de l'interface de Java8 est d'introduire des méthodes par défaut, afin que nous puissions fournir des implémentations par défaut des méthodes dans l'interface. Cependant, peu importe le nombre de méthodes par défaut, tant que l'on a et une seule méthode abstraite, il s'agit d'une interface fonctionnelle, comme suit (reportez-vous à l'AppleFilter ci-dessus):
/ *** Interface du filtre Apple * / @ FunctionalInterfacePublic Interface Applefilter {/ *** Condition de filtre Résumé ** @param Apple * @ return * / boolean accepter (Apple Apple);}AppleFilter ne contient qu'une méthode abstraite accepter (Apple Apple). Selon la définition, il peut être considéré comme une interface fonctionnelle. Lors de la définition, nous ajoutons l'annotation @FunctionalInterface à l'interface pour marquer l'interface en tant qu'interface fonctionnelle. Cependant, cette interface est facultative. Après avoir ajouté cette interface, le compilateur restreint l'interface pour avoir uniquement une méthode abstraite, sinon une erreur sera signalée, il est donc recommandé d'ajouter cette annotation à l'interface fonctionnelle.
JDK est livré avec une interface fonctionnelle:
JDK est une expression de lambda avec de riches interfaces fonctionnelles. Vous trouverez ci-dessous des exemples d'utilisation du prédicat <T>, du consommateur <T>, de la fonction <T, R> respectivement.
Prédicat:
@FunctionalInterFacePublic Interface Predicate <T> {/ *** évalue cette prédire sur l'argument donné. ** @param t L'argument d'entrée * @return {@code true} Si l'argument d'entrée correspond à la prévision, * sinon {@code false} * / booléen test (t t);};La fonction du prédicat est similaire à l'AppleFilter ci-dessus. Il utilise les conditions que nous définissons en externe pour vérifier les paramètres entrants et renvoie le résultat de vérification booléen. Le prédicat des utilités suivantes pour filtrer les éléments de la collection de liste:
/ **** @param List * @param Predicat * @param <T> * @ return * / public <T> list <T> Filter (list <T> list, prédicat <T> Predicat) {list <t> newlist = new ArrayList <T> (); for (final t: list) {if (prédicat.test (t)) {newlist.add (t);}}utiliser:
Demo.Filter (list, (String str) -> null! = str &&! str.iSempty ());
Consommateur
@FunctionalInterfacePublic Interface Consumer <T> {/ *** Effectue cette opération sur l'argument donné. ** @param t L'argument d'entrée * / void accepte (t t);}Le consommateur fournit une fonction abstraite d'accepter qui reçoit des paramètres mais ne renvoie pas de valeurs. Ce qui suit utilise le consommateur pour traverser la collection.
/ *** Traversement de la collection et effectuer un comportement personnalisé ** @param liste * @param consommateur * @param <T> * / public <T> void Filter (list <T> list, Consumer <T> Consumer) {for (final t: list) {Consumer.Accept (t);}}À l'aide de l'interface fonctionnelle ci-dessus, parcourez la collection de chaînes et imprimez les chaînes non vides:
Demo.Filter (list, (String str) -> {if (stringUtils.isnotblank (str)) {System.out.println (str);}});Fonction
@FunctionalInterFacePublic Interface Fonction <T, R> {/ *** applique cette fonction à l'argument donné. ** @param t L'argument de la fonction * @return le résultat de la fonction * / r applique (t t);}La fonction effectue une opération de conversion. L'entrée est des données de type T et renvoie les données du type R. La fonction utilise suivante pour convertir l'ensemble:
public <t, r> list <r> filter (list <t> list, function <t, r> function) {list <r> newList = new ArrayList <r> (); pour (final t t: list) {newlist.add (function.apply (t));} return newlist;}autre:
Demo.Filter (List, (String Str) -> Integer.ParseInt (Str));
Les interfaces fonctionnelles ci-dessus fournissent également certaines implémentations par défaut des opérations logiques. Parlons-en plus tard lors de l'introduction des méthodes par défaut de l'interface Java8 ~
Certaines choses à faire attention pendant l'usage:
Type d'inférence:
Pendant le processus de codage, nous pouvons parfois nous demander quelle interface fonctionnelle que notre code d'appel correspondra. En fait, le compilateur portera des jugements corrects en fonction des paramètres, du type de retour, du type d'exception (si présent), etc.
Lorsque vous appelez de manière spécifique, le type de paramètre peut être omis à certains moments, ce qui simplifie davantage le code:
// Filter Apple List <Pomme> FilterApples = FilterApplesByAppleFilter (pommes, (Apple Apple) -> Color.red.equals (Apple.getColor ()) && Apple.getweight ()> = 100); // Dans certains cas, nous pouvons même omettre les types de paramètres, et le compilateur jugera correctement la liste <mele> FilterApple = FilterApplesBy Color.red.equals (Apple.getColor ()) && apple.getweight ()> = 100);
Variables locales
Tous les exemples au-dessus de nos expressions lambda utilisent leurs paramètres corporels, nous pouvons également utiliser des variables locales en lambda, comme suit
int Weight = 100; list <pple> filterApples = FilterApplesByAppleFilter (pommes, Apple -> Color.red.equals (Apple.getColor ()) && Apple.getweight ()> = poids);:
Dans cet exemple, nous utilisons le poids variable local dans la lambda. Cependant, l'utilisation de variables locales dans le lambda doit exiger que la variable soit explicitement déclarée comme finale ou en fait final. Cela est principalement dû au fait que la variable locale est stockée sur la pile, et l'expression de lambda est exécutée dans un autre thread. Lorsque la vue de thread accède à la variable locale, la variable a la possibilité d'être modifiée ou recyclée, il n'y aura donc pas de problèmes de sécurité du fil après modification avec final.
Iv. Citation de la méthode
L'utilisation de références de méthode peut rendre le code plus simplifié. Parfois, cette simplification rend le code plus intuitif. Jetons un coup d'œil à un exemple:
/ * ... omettre l'opération d'initialisation des pommes * /// Utilisez l'expression de lambda pommes.sort ((Apple A, Apple B) -> float.C.
Les références de méthode connectent l'appartenance à la méthode et la méthode elle-même à travers ::, qui sont principalement divisées en trois catégories:
Méthode statique
(args) -> className.staticMethod (args)
Se convertir
ClassName :: StaticMethod
Exemple de méthode de paramètre
(args) -> args.InstanceMethod ()
Se convertir
ClassName :: instanceMethod // classname est type args
Méthode d'instance externe
(args) -> ext.instancethod (args)
Se convertir
ext :: instanceMethod (args)
se référer à:
http://www.codeceo.com/article/lambda-of-java-8.html
Ce qui précède est l'expression lambda de la nouvelle fonctionnalité JDK8 que l'éditeur vous a introduit. J'espère que cela vous sera utile. Si vous avez des questions, veuillez me laisser un message et l'éditeur vous répondra à temps. Merci beaucoup pour votre soutien au site Web Wulin.com!