2
votes

Question concernant l'interface fonctionnelle en Java8

Comment la méthode apply () fonctionne-t-elle en Java?

Concernant l'interface fonctionnelle d'UnaryOperator, j'ai lu la documentation, elle dit

    new Stream().map(new Uppercase())

Représente une opération sur un opérande unique qui produit un résultat du même type que son opérande. Il s'agit d'une spécialisation de Function pour le cas où l'opérande et le résultat sont du même type. Il s'agit d'une interface fonctionnelle dont la méthode fonctionnelle est Function.apply(Object).

Quelle est la méthode fonctionnelle?

J'ai la classe suivante qui implémente l'interface UnaryOperator.

    public class Uppercase implements UnaryOperator<String> {
        @Override
        public String apply(String s) {
            return s.trim().toUpperCase();
        }
    }

Dans l'appel de méthode,

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T,T>

Il convertit tout flux d'entrée en majuscules. Ma question est la suivante: la méthode apply () de la classe Uppercase est-elle appelée automatiquement? (Est-ce comme si la méthode toString () est appelée automatiquement par la méthode println () ?)

Je n'ai trouvé aucun exemple sans appeler apply () explicitement. Alors s'il vous plaît, aidez-moi à comprendre ce qui s'est passé ici.


2 commentaires

Avez-vous utilisé votre moteur de recherche préféré pour rechercher interface fonctionnelle java et lu l’une des excellentes descriptions de son fonctionnement? On s'attend à ce qu'avant de poser une question fondamentale comme celle-ci, vous ayez fait quelques recherches.


il vaut également la peine de consulter la documentation avec laquelle presque chaque classe / interface est fournie: FunctionalInterface et la spécification du langage Java: JLS §9.8


4 Réponses :


2
votes

La méthode apply () de la classe Uppercase est-elle appelée automatiquement?

La méthode map implémentée dans Stream est chargée d'appeler la méthode apply de la Function que vous ai créé.

Remarque : Majuscule implémente UnaryOperator étend la Function qui est l'endroit où le La mise en œuvre de apply que vous avez définie est appelée.


0 commentaires

2
votes

Il convertit tout flux d'entrée en majuscules. Ma question est, est-ce que la méthode apply () de la classe Uppercase est appelée automatiquement?

En effet, c'est le rôle de l'implémentation Stream.map () d'appeler apply () dessus, donc vous ne le ferez jamais lorsque Stream.map () est appelée.

La classe abstraite ReferencePipeline fait cela:

new Stream().map(s->s.trim().toUpperCase())....

map ( ) défini dans Stream est déclaré comme:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

Stream.map () attend une Function et en passant un UnaryOperator vous fournissez tout ce qui est nécessaire.

Je n'ai trouvé aucun exemple sans appeler explicitement la méthode apply (). Alors, aidez-moi à comprendre ce qui s’est passé ici.

En général, vous n'implémentez pas directement l'interface fonctionnelle mais vous passez un lambda car c'est plus simple:

@SuppressWarnings("unchecked")
public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
    Objects.requireNonNull(mapper);
    return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
                                 StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
        @Override
        Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
            return new Sink.ChainedReference<P_OUT, R>(sink) {
                @Override
                public void accept(P_OUT u) {
                    downstream.accept(mapper.apply(u)); // <------ HERE 
                }
            };
        }
    };
}

0 commentaires

3
votes

Oui, c'est exactement comme la fonction toString () invoque dans la fonction println () . println () accepte tous les objets, donc par défaut toString () hérite de la classe java.lang.Object ainsi que de Stream La fonction map () de la classe accepte les objets de type java.util.function.Function dont vous avez exactement fait l'implémentation avec la classe Uppercase .

En ce qui concerne les interfaces fonctionnelles, l'interface fonctionnelle n'est pas seulement une interface décorée avec l'annotation @FunctionalInterface . L'interface fonctionnelle ne peut avoir qu'une seule méthode d'instance. Pourrait avoir de nombreuses méthodes static et default cependant. Ces interfaces ont essentiellement été introduites pour fonctionner avec le nouveau type de syntaxe de Java 8 appelé Expressions Lambda . Sinon, ce n'est qu'une interface.

Votre solution implémente comme ceci si vous le souhaitez, créant une classe interne anonyme;

new Stream().map(s -> s.trim().toUpperCase());

Pas besoin de déclarer une classe concrète distincte comme Majuscule . Avec l'expression lambda, vous pouvez raccourcir le code comme ceci;

new Stream().map(new Function() {

    @Override
    public String apply(String s) {
        return s.trim().toUpperCase();
    }
});

Ceci est l'utilisation des méthodes fonctionnelles des interfaces fonctionnelles. Cela n'est possible que lorsqu'il n'y a qu'une seule méthode d'instance . Pas besoin d'implémenter une classe séparée comme vous l'avez fait.


0 commentaires

0
votes

En informatique, Apply est une fonction qui applique des fonctions aux arguments.

C'est peut-être nouveau pour Java, mais c'est courant dans la programmation fonctionnelle. L'objet peut être traité comme une fonction qui a la méthode apply. Ainsi, lorsqu'un nouvel objet est créé, la méthode apply sera exécutée avec les arguments passés.

La réponse de Vlad Gudim a été détaillée: https://stackoverflow.com/a/9738862/3812323 < / p>

C'est pour la scala, mais c'est vrai dans le paradigme fonctionnel.


0 commentaires