Java 8 a des fonctionnalités améliorées autour de la programmation fonctionnelle.
Résumez les fonctions des interfaces fonctionnelles et les références de méthodes
Goal Vous pourrez lire et utiliser ce code source.
public static void main(String[] args) {
List<String> strings = Arrays.asList("bravo", "", "charlie", "alpha");
strings.stream()
.filter(s -> !s.isEmpty())
.map(s -> s.substring(0, 1).toUpperCase() + s.substring(1))
.forEach(System.out::println);
// Bravo
// Charlie
// Alpha
}
Qu'est-ce qu'une interface fonctionnelle et à quoi sert-elle? Pour le comprendre, il est nécessaire de comprendre le concept de ** fonction primaire **.
Une fonction de première classe (anglais: fonction de première classe) [1] est la nature d'un langage de programmation qui peut traiter une fonction comme un objet de première classe, ou une telle fonction. C'est.
Objet de première classe?
Les objets de première classe sont des opérations de base illimitées dans un langage de programmation, telles que la génération, l'affectation, l'arithmétique et la transmission (en tant qu'arguments / valeurs de retour). C'est un objet qui peut être utilisé.
je vois
Les fonctions Java (méthodes) ne peuvent pas être affectées à des variables ou utilisées pour les valeurs / arguments de retour. Java est un langage qui ne répond pas aux propriétés des fonctions de première classe.
Les fonctions de premier ordre sont essentielles pour les langages fonctionnels et sont couramment utilisées sous la forme de fonctions d'ordre supérieur.
** Le comportement peut être manipulé par des fonctions de l'extérieur. ** ** ex. règles de tri
List<String> strings = Arrays.asList("bravo", "charlie", "alpha");
Collections.sort(strings);
System.out.println(strings); // -> [alpha, bravo, charlie]
Collections.sort(strings, Comparator.reverseOrder());
System.out.println(strings); // -> [charlie, bravo, alpha]
Benri.
N'est-ce pas le code Java actuel?
Un modèle de conception conçu parce que la fonction ne peut pas être utilisée comme objet principal.
Java vous permet d'implémenter des modèles de stratégie en utilisant le polymorphisme avec des substitutions de méthode de classe.
Je vais omettre les détails, mais cela ressemble à ceci.
public static <T> void sort(List<T> list, Comparator<? super T> c) {
if (c.compare(a, b) < 0) {
//a est plus petit
}else {
//b est plus petit
}
}
La règle de tri est déterminée en fonction de la classe d'implémentation de l'interface Comparator reçue en argument. La pratique selon laquelle la méthode elle-même n'est pas transmise via un argument, mais le traitement de la méthode peut être passé de l'extérieur via l'interface.
Le processus de tri actuel ressemble à ceci jdk/TimSort.java at master · openjdk/jdk
Ce modèle de conception n'a pas besoin d'être particulièrement visible dans les langages où la fonction est un objet principal.
Ce modèle est implicitement utilisé dans les langages où la fonction est un objet principal.
Java peut gérer des fonctions (méthodes) comme des objets de première classe à l'aide d'interfaces.
Depuis java8, l'interface utilisée pour traiter une fonction (méthode) comme un objet de première classe comme le comparateur précédent est appelée ** interface fonctionnelle **. Puisque le but est de traiter les fonctions (méthodes) comme des objets de première classe, il n'y a qu'une seule méthode abstraite pour les interfaces fonctionnelles.
Certaines des interfaces qui ont été fournies dans le passé, telles que Comparator et Runnable, viennent de recevoir de nouveaux noms. La fonction est la même qu'une interface normale. L'annotation ** @ FunctionalInterface ** a été ajoutée à l'interface fonctionnelle. e.g. java.lang.Runnable
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface {@code Runnable} is used
* to create a thread, starting the thread causes the object's
* {@code run} method to be called in that separately executing
* thread.
* <p>
* The general contract of the method {@code run} is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
jdk/FunctionalInterface.java at master · openjdk/jdk
@FunctionalInterface Annotations ajoutées pour les interfaces fonctionnelles. Rien ne se passe lors de l'exécution (l'interface fonctionnelle est fonctionnellement une interface normale, il n'y a donc pas de traitement spécial). Au moment de la compilation, il vérifiera s'il répond aux propriétés de l'interface fonctionnelle.
En d'autres termes, cela n'est pas absolument nécessaire lors de l'utilisation des fonctions de l'interface fonctionnelle. Cependant, comme on peut clairement affirmer qu'il s'agit d'une interface fonctionnelle plutôt qu'une interface normale, il semble qu'elle devrait être ajoutée lors de la création d'une interface fonctionnelle.
Lors de la manipulation d'une fonction (méthode) à l'aide d'une interface fonctionnelle, la méthode à gérer est affectée par le système de type Java. Plus précisément, lorsqu'il s'agit de différentes méthodes ci-dessous, différentes interfaces fonctionnelles doivent être utilisées.
--Type de retour --Type d'argument --Nombre d'arguments
java8 fournit une interface fonctionnelle standard qui résume et rend disponible la présence / absence d'une valeur de retour et le type d'un argument. Fondamentalement, cette interface est suffisante, et il est dit que vous devriez envisager d'utiliser cette interface. (Sauf pour les habituels tels que Runnable)
** Interface fonctionnelle standard typique **
Nom de l'interface | Nom de la méthode abstraite | Exemple |
---|---|---|
Function<T,R> | R apply(T t) | Arrays::asList |
Predicate |
boolean test(T t) | Collections::isEmpty |
Consumer<T> | void accept(T t) | System.out::println |
Supplier<T> | T get() | Instant::now |
UnaryOperator<T> | T apply(T t) | String::toLowerCase |
BinaryOperator<T> | T apply(T t1, T t2) | BigInteger::add |
java.util.function (Java Platform SE 8 )
Créons un processus pour traiter et générer une chaîne de caractères. Lors de l'appel du processus à sortir, la chaîne de caractères après le processus d'usinage est sortie en transmettant la fonction de processus d'usinage ensemble. Essayez de créer un programme qui sort après avoir tout converti en majuscules.
Sortie après l'exécution de la fonction passée.
L'interface fonctionnelle suppose une fonction qui reçoit une chaîne avant la modification (String) et renvoie la chaîne après la modification (String), et utilise ʻUnaryOperator
static void print(String word, UnaryOperator<String> operator) {
String newWord = operator.apply(word);
System.out.println(newWord);
}
Une fonction qui se convertit en majuscules.
ʻImplement UnaryOperator
import java.util.function.UnaryOperator;
public class MyUpperOperator implements UnaryOperator<String> {
@Override
public String apply(String s) {
return s.toUpperCase();
}
}
main Si vous passez la fonction de conversion des majuscules créée précédemment et la chaîne de caractères à la méthode d'impression, elles seront affichées en majuscules.
public static void main(String[] args) {
UnaryOperator<String> upperOperator = new MyUpperOperator();
print("hello world", upperOperator); // -> HELLO WORLD
}
Il utilise une interface fonctionnelle, mais ce n'est qu'un modèle de stratégie.
Dans l'exemple précédent, en fait, un style d'écriture plus puissant est possible.
En utilisant une fonction appelée ** method reference **, il est possible de passer directement une méthode dont l'argument et la valeur de retour correspondent sans implémenter explicitement une interface fonctionnelle.
Dans le cas de l'exemple précédent, puisque ʻUnaryOperator , si la méthode est constituée d'une seule chaîne et que la valeur de retour est String, elle peut être passée directement comme référence de méthode. Vous pouvez directement affecter la méthode
toUpperCase ()de la
String class à l'instance ʻUnaryOperator <String>
.
(Dans le cas d'une référence de méthode d'une méthode d'instance, l'objet récepteur est interprété comme le premier argument. Voir la syntaxe ci-dessous.)
Lorsque cela se produit, le code source appelant semble traiter la fonction comme un objet de première classe.
public static void main(String[] args) {
// UnaryOperator<String> upperOperator = new MyUpperOperator();
UnaryOperator<String> upperOperator = String::toUpperCase;
print("hello world", upperOperator); // -> HELLO WORLD
}
Il semble qu'il utilise l'instruction ʻinvoke Dynamic` de JVM. Il semble que la classe soit générée et résolue dynamiquement au moment de l'exécution, pas au moment de la compilation.
Notation de deux points-virgules consécutifs. Le contenu décrit des deux côtés du point-virgule peut être divisé en quatre modèles selon le type de méthode.
Cible | grammaire | Exemple |
---|---|---|
Méthode de classe | nom de la classe::Nom de la méthode de classe | String::toString |
Méthode d'instance | Nom de l'instance::Nom de la méthode d'instance | System.out::println |
Méthode d'instance * | nom de la classe::Nom de la méthode d'instance | String::toUpperCase |
constructeur | nom de la classe::new | String::new |
L'exemple précédent peut être décrit très brièvement. La classe MyUpperOperator n'est plus nécessaire.
public static void main(String[] args) {
print("hello world", String::toUpperCase); // -> HELLO WORLD
}
De plus, de nombreuses API de flux ajoutées dans java8 nécessitent une interface fonctionnelle, ce type de traitement peut donc être effectué.
public static void main(String[] args) {
List<String> strings = Arrays.asList("bravo", "charlie", "alpha");
strings.stream()
.map(String::toUpperCase)// Function:Convertir en majuscules
.forEach(System.out::println);// Consumer:production
// BRAVO
// CHARLIE
// ALPHA
}
Il est nécessaire de déclarer la méthode à l'avance pour pouvoir la gérer. Il est bon d'utiliser les méthodes fournies, mais vous devez déclarer votre propre traitement en tant que méthode une par une. Je veux traiter la méthode comme un littéral.
Mécanisme de formule d'évaluation pouvant être affecté à une interface fonctionnelle. Vous pouvez écrire une méthode en tant qu'expression sans déclarer la méthode.
par exemple, fonction pour ajouter un point à la chaîne
public static void main(String[] args) {
// UnaryOperator<String> upperOperator = String::toUpperCase;
UnaryOperator<String> periodOperator = (String s) -> { return s + "."; };
print("hello world", periodOperator); // -> hello world.
}
Ceci est la forme de base
(Chaîne d'argument formel) -> {Traitement du corps de l'instruction}
e.g.
(String s) -> { return s + "."; }
Diverses descriptions ne peuvent être omises que sous certaines conditions.
Je vais l'omettre parce que je pense que diverses choses ressortiront si je la recherche.
par exemple dans ce cas
UnaryOperator<String> periodOperator = s -> s + ".";
public static void main(String[] args) {
print("hello world", s -> s + "."); // -> hello world.
}
public static void main(String[] args) {
List<String> strings = Arrays.asList("bravo", "", "charlie", "alpha");
strings.stream()
.filter(s -> !s.isEmpty()) // Predicate:Supprimer les caractères vides
.map(s -> s.substring(0, 1).toUpperCase() + s.substring(1)) // Function:Convertir uniquement le premier caractère en majuscule
.forEach(System.out::println); // Consumer:production
// Bravo
// Charlie
// Alpha
}
Un exemple de ce dernier est le processus mentionné au début de cet article.
Vous pourrez lire et utiliser ce code source.
La programmation fonctionnelle a été améliorée depuis java8.
Perfect Java 2e édition révisée: Guide du livre | Revue technique Effective Java 3rd Edition-Maruzen Publishing, un éditeur de livres spécialisé dans les domaines des sciences, de l'ingénierie, de la médecine et des sciences humaines et sociales
Recommended Posts