Java 8 Lambda Expressions-qu'en est-il des méthodes multiples dans la classe imbriquée


Je lis sur les nouvelles fonctionnalités à: http://www.javaworld.com/article/2078836/java-se/love-and-hate-for-java-8.html

J'ai vu l'exemple ci-dessous:

Utilisation de la classe anonyme:

button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent ae) {
        System.out.println("Action Detected");
    }
});

Avec Lambda:

button.addActionListener(e -> {
    System.out.println("Action Detected");
});

Que ferait quelqu'un avec un {[3] } s'il voulait implémenter plusieurs méthodes dans la classe anonyme, par exemple:

public void mousePressed(MouseEvent e) {
    saySomething("Mouse pressed; # of clicks: "
               + e.getClickCount(), e);
}

public void mouseReleased(MouseEvent e) {
    saySomething("Mouse released; # of clicks: "
               + e.getClickCount(), e);
}

... et ainsi de suite?

Author: MC Emperor, 2014-02-17

5 answers

À Partir de JLS 9.8

Une interface fonctionnelle est une interface qui n'a qu'une seule méthode abstraite, et donc représente un contrat de fonction unique.

Les lambdas nécessitent ces interfaces fonctionnelles et sont donc limités à leur méthode unique. Les interfaces anonymes doivent encore être utilisées pour implémenter des interfaces multi-méthodes.

addMouseListener(new MouseAdapter() {

    @Override
    public void mouseReleased(MouseEvent e) {
       ...
    }

    @Override
    public void mousePressed(MouseEvent e) {
      ...
    }
});
 76
Author: Reimeus, 2014-02-17 17:01:46

Vous pouvez utiliser des interfaces multi-méthodes avec les lambdas en utilisant des interfaces d'assistance. Cela fonctionne avec de telles interfaces d'écoute où les implémentations de méthodes indésirables sont triviales (c'est-à-dire que nous pouvons simplement faire ce que MouseAdapter offre aussi):

// note the absence of mouseClicked…
interface ClickedListener extends MouseListener
{
    @Override
    public default void mouseEntered(MouseEvent e) {}

    @Override
    public default void mouseExited(MouseEvent e) {}

    @Override
    public default void mousePressed(MouseEvent e) {}

    @Override
    public default void mouseReleased(MouseEvent e) {}
}

Vous n'avez besoin de définir une telle interface d'aide qu'une seule fois.

Maintenant, vous pouvez ajouter un écouteur pour cliquez-événements sur un Component c comme ceci:

c.addMouseListener((ClickedListener)(e)->System.out.println("Clicked !"));
 62
Author: Holger, 2014-02-18 10:37:00

L'EG Lambda a examiné cette question. De nombreuses bibliothèques utilisent des interfaces fonctionnelles, même si elles ont été conçues des années avant que l'interface fonctionnelle ne devienne une chose. Mais il arrive parfois qu'une classe ait plusieurs méthodes abstraites, et vous ne voulez cibler qu'une d'entre elles avec un lambda.

Le modèle officiellement recommandé ici est de définir les méthodes d'usine:

static MouseListener clickHandler(Consumer<MouseEvent> c) { return ... }

Ceux-ci peuvent être effectués directement par les API elles-mêmes (il pourrait s'agir de méthodes statiques à l'intérieur de MouseListener) ou pourrait être des méthodes d'aide externes dans une autre bibliothèque si les mainteneurs choisissent de ne pas offrir cette commodité. Parce que l'ensemble des situations où cela était nécessaire est petit, et la solution de contournement est si simple, il ne semblait pas convaincant d'étendre davantage le langage pour sauver ce cas de coin.

Une astuce similaire a été utilisée pour ThreadLocal; voir la nouvelle méthode d'usine statique withInitial(Supplier<S>).

(En passant, lorsque ce problème survient, l'exemple est presque toujours MouseListener, qui est encourageant comme il le suggère l'ensemble des classes qui aimeraient être lambda friendly, mais ne le sont pas, est en fait assez petit.)

 27
Author: Brian Goetz, 2017-08-17 02:21:22

Un Java ActionListener doit implémenter une seule méthode (actionPerformed(ActionEvent e)). Cela s'intègre bien dans la fonction Java 8 donc Java 8 fournit un lambda simple pour implémenter un ActionListener.

Le MouseAdapter nécessite au moins deux méthodes, donc ne correspond pas à un function.

 4
Author: OldCurmudgeon, 2014-02-17 17:19:39

Les méthodes par défaut ne sont pas accessibles depuis les expressions lambda. Le code suivant ne compile pas:

interface Formula {
    double calculate(int a);

    default double sqrt(int a) {
        return Math.sqrt(a);
    }
}
Formula formula = (a) -> sqrt( a * 100);

Ne fonctionne qu'avec une interface fonctionnelle (méthode abstraite unique uniquement +n'importe quel nombre de méthodes par défaut), donc lambda expresion fonctionne avec uniquement la méthode abstraite

 -3
Author: Ranjeet Singh Rajpurohit, 2016-04-27 01:24:26