Pour exécuter un thread en Java, utilisez une sous-classe qui hérite de la classe Thread, et Il existe une méthode utilisant une sous-classe qui implémente l'interface Runnable. Cette fois, ce dernier est pris comme exemple pour une brève explication de l'expression lambda.
Function.java
public class Function implements Runnable{
@Override
public void run() {
//Que traiter dans le fil
System.out.println("hello!");
}
}
Main.java
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new Function());
thread.start();
System.out.println("finish!");
}
}
Je pense que la sortie ressemblera à ceci.
finish!
hello!
Quelle est la relation entre la classe Thread et l'interface Runnable? La conception du modèle de stratégie du modèle de conception du GoF est utilisée. En gros, le modèle de stratégie est conçu pour «réaliser un algorithme remplaçable». La classe qui en était à l'origine est en charge du flux global de traitement, Divisons-le en classes qui sont en charge d'algorithmes spécifiques. En utilisant le modèle de stratégie, avec l'utilisateur (classe Thread) Le côté à utiliser (la classe qui réalise l'interface Runnable) Puisqu'il n'a pas à être directement lié, il est possible de réaliser un algorithme qui peut être remplacé plus tard. (Pour ceux qui veulent en savoir plus sur les modèles de stratégie, voir ici) Cependant, la classe qui réalise l'interface est compliquée (classe FunctionHard dans le diagramme UML). Il y a quelque chose comme une classe qui nécessite un code simple (classe FunctionEasy dans le diagramme UML).
Nouvelles classes une par une, même avec du code simple N'est-ce pas ennuyeux d'avoir à définir? à propos de ça.
Afin de résoudre le problème présenté dans l'introduction, nous utiliserons l'expression lambda introduite à partir de Java SE 8. Le code suivant est remplacé par une expression lambda au lieu de créer une classe FunctionEasy.
Lambda.java
public class Lambda {
public static void main(String[] args) {
Runnable r = () -> System.out.println("hello!");
Thread thread = new Thread(r);
thread.start();
System.out.println("finish!");
}
}
Vous n'avez besoin que d'une seule ligne comme celle-ci. Rafraîchissant! Les expressions Lambda sont "lors de l'instanciation d'une interface fonctionnelle Vous pouvez le considérer comme «une notation qui ne nécessite pas d'écriture compliquée».
Une interface qui n'a qu'une seule méthode à implémenter est appelée "interface fonctionnelle" Elle est également appelée "interface SAM (Single Abstarct Method)".
Comme vous pouvez le voir sur SAM, il n'a qu'une seule méthode abstraite, donc Quelle méthode est implémentée par l'expression lambda? Qu'en est-il des arguments et des valeurs de retour? L'inférence est possible. Il n'est pas nécessaire de décider le nom de la méthode un par un. Le polymorphisme peut être réalisé sans préparer une classe qui réalise l'interface.
Avant Java8, il était réalisé par une classe anonyme. Les classes anonymes sont parfois appelées classes anonymes.
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("hello!");
}
}
C'est long et illisible.
Les expressions Lambda sont apparues dans Java 8 et il est devenu plus facile de les écrire.
Runnable r = () -> {
System.out.println("hello!");
}
La déclaration d'expression lambda se compose de la déclaration de variable d'argument et du bloc de traitement comme indiqué ci-dessous.
(argument) -> {En traitement; };
"->" Est appelé un opérateur de flèche.
Certaines expressions lambda peuvent être omises. Suivons le prototype suivant à titre d'exemple.
prototype
Sample sample = (String a) -> { System.out.println(a);};
Si l'argument est ** uniquement lorsqu'il y en a un **, les parenthèses "()" peuvent être omises. En outre, le type de l'argument peut être déduit, de sorte qu'il peut être omis.
Abréviation notation 1
Sample sample = a -> { System.out.println(a);};
De même, si le corps de la méthode est une ligne, la parenthèse du milieu "{}" et le point-virgule ";" à la fin de la phrase peuvent être omis. Dans le cas d'une instruction return, return peut également être omis.
Abréviation notation 2
Sample sample = a -> System.out.println(a);
De plus, si l'argument peut être déduit, l'appel de la méthode Nom de la classe :: Nom de la méthode Nom de l'objet :: Nom de la méthode Il peut être omis comme ça.
Notation d'abréviation 3
Sample sample = System.out::println;
** Une variable portant le même nom que la variable locale déclarée dans la méthode ne peut pas être utilisée comme nom d'argument de l'expression lambda. ** ** Ce qui suit entraînera une erreur de compilation.
public class Sample {
public static void main(String[] args) {
String a = "sample";
Function f = a -> System.out.println(a); //Erreur
//Abréviation
}
}
Comme le nom de variable a a déjà été déclaré en tant que variable locale, il ne peut pas être utilisé comme nom d'argument pour une expression lambda.
** Pour accéder à une variable locale déclarée en dehors de l'expression lambda à partir de l'expression lambda, la variable locale doit être finale. Si le modificateur final n'est pas joint, il doit être final pratique. ** **
Vous pouvez accéder aux variables locales de la méthode qui entoure l'expression à partir de l'expression lambda. (Si vous y réfléchissez avant la conversion en expression lambda, c'est comme ça.) Vous pouvez accéder aux variables locales de la méthode qui déclare l'expression à partir de l'expression lambda comme suit:
«Substantiellement définitive» signifie une variable qui ne change pas, même si elle n'est pas qualifiée de manière définitive. Si vous modifiez la valeur d'une variable locale dans une expression lambda comme indiqué ci-dessous, une erreur de compilation se produit.
public class Sample {
public static void main(String[] args) {
String a = "sample";
Function f = () -> {
a = "change"; //Erreur
System.out.println(a);
};
//Abréviation
}
}
Les interfaces fonctionnelles fréquemment utilisées se trouvent dans le package java.util.function. En particulier, les cinq interfaces fonctionnelles suivantes sont célèbres.
Interface fonctionnelle | Méthode | argument | Valeur de retour | La description |
---|---|---|---|---|
Consumer<T> | void accept(T) | Oui | Aucun | "Consommateur" qui ne renvoie pas de valeur |
Supplier<T> | T get() | Aucun | Oui | "Fournisseur" renvoyant une valeur |
Predicate<T> | boolean test(T) | Oui | Oui | "Affirmation" qui renvoie une valeur booléenne |
Function<T, R> | R apply(T) | Oui | Oui | "Traitement" qui reçoit un argument et renvoie le résultat du type spécifié |
UnaryOperator<T> | T apply(T t) | Il y en a deux | Oui | "Opération" qui renvoie le résultat du calcul |
L'API Collection a de nombreuses méthodes par défaut pour manipuler List et Map.
Par exemple, java.util.List a une méthode appelée * removeIf (Predicate filter) * qui supprime les éléments qui correspondent au filtre. Si vous utilisez l'expression lambda, vous n'avez besoin que d'une seule ligne.
RemoveIf.java
import java.util.ArrayList;
import java.util.Arrays;
public class RemoveIf {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>(Arrays.asList("aaaa", "bbb", "cc"));
list.removeIf(v -> v.length() > 3);
System.out.println(list); //résultat: [bbb, cc]
}
}
Il existe de nombreuses autres méthodes qui vous permettent de spécifier une expression lambda. Examinons par vous-même et implémentons-le avec une expression lambda pour nous y habituer.
Il existe de nombreuses applications WEB dont le côté serveur s'exécute sous Java 8. Par conséquent, je pense que l'expression lambda et l'API Stream sont des connaissances inévitables lorsque vous utilisez Java maintenant. Néanmoins, il semble que certaines choses ne sont pas enseignées dans la formation des nouveaux arrivants Java. J'ai essayé de le résumer le plus facilement possible pour les nouveaux arrivants. Je suis désolé s'il y a une partie difficile à comprendre.
La prochaine fois, je résumerai l'introduction à l'API Stream dans la semaine prochaine.
(Mis à jour le 22 décembre 2019) Sequel Something → [Java] Introduction to Stream API
Recommended Posts