Java et fonctions principales - au-delà de l'interface fonctionnelle -

Aperçu

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
}

Interface fonctionnelle

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 **.

Fonction de première classe

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?

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

Et Java?

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.

Qu'est-ce qui vous rend heureux avec une fonction 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.

attends une minute

N'est-ce pas le code Java actuel?

Modèle de stratégie

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.

Réel

Java peut gérer des fonctions (méthodes) comme des objets de première classe à l'aide d'interfaces.

Qu'est-ce qu'une interface fonctionnelle?

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.

Interface fonctionnelle standard

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 )

En fait utiliser

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.

Partie d'affichage de chaîne de caractères

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);
}

Fonction à passer

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
}

bien

Il utilise une interface fonctionnelle, mais ce n'est qu'un modèle de stratégie.

Référence de la méthode

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 laString 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
}

Comment ça marche est difficile

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.

grammaire

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

Essayez d'utiliser

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
}

Très pratique, mais

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.

Style Lambda

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.
}

grammaire

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 + ".";

Essayez d'utiliser

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.

Résumé

La programmation fonctionnelle a été améliorée depuis java8.

référence

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

Java et fonctions principales - au-delà de l'interface fonctionnelle -
Java et JavaScript
XXE et Java
[Java] Interface fonctionnelle
Efficacité de Java 3rd Edition Chapitre 4 Classes et interfaces
Getter et Setter (Java)
[Java] Thread et exécutable
interface de type de fonction standard java
Java vrai et faux
[Java] Comparaison des chaînes de caractères et && et ||
Java - Sérialisation et désérialisation
[Java] Arguments et paramètres
timedatectl et Java TimeZone
[Java] Branchement et répétition
[Java] Types de variables et types
java (classe et instance)
[Java] Surcharge et remplacement
Etudier Java # 2 (\ marque et opérateur)
Java version 8 et fonctionnalités ultérieures
[Java] Interface fonctionnelle / expression lambda
[Java] Différence entre == et égal
[Java] Zone de pile et zone statique
[Java] Classe générique et méthode générique
Essayez le type fonctionnel en Java! ①
Programmation Java (variables et données)
Cryptage et décryptage Java PDF
Java et Iterator Part 1 External Iterator Edition
Instructions Java if et switch
Définition et instanciation de classe Java
Apache Hadoop et Java 9 (partie 1)
[Java] À propos de String et StringBuilder
[Java] HashCode et remplacement égal
☾ Instruction Java / Repeat et instruction de contrôle de répétition
Méthodes Java et surcharges de méthodes
java Generics T et? Différence
Avantages et inconvénients de Java
java (branchement conditionnel et répétition)
Implémenter un tri rapide de type fonction en Java
À propos du package Java et de l'importation
[Java] Téléchargez une image et convertissez-la en Base64
Histoire de remplacement C # et Java
Méthodes et classes abstraites Java
Instructions Java while et for
Encapsulation Java et getters et setters