tutorial - Java 8 Lambda Expressions: ¿qué pasa con los métodos múltiples en la clase anidada?
java 8 stream (5)
De JLS 9.8
Una interfaz funcional es una interfaz que tiene solo un método abstracto y, por lo tanto, representa un contrato de función única.
Lambdas requiere estas interfaces funcionales por lo que están restringidas a su único método. Las interfaces anónimas aún deben ser utilizadas para implementar interfaces de múltiples métodos.
addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
...
}
@Override
public void mousePressed(MouseEvent e) {
...
}
});
Estoy leyendo sobre las nuevas características en: http://www.javaworld.com/article/2078836/java-se/love-and-hate-for-java-8.html
Vi el ejemplo a continuación:
Usando la clase anónima:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.out.println("Action Detected");
}
});
Con Lambda:
button.addActionListener(e -> {
System.out.println("Action Detected");
});
¿Qué haría alguien con un MouseListener
si quisieran implementar múltiples métodos dentro de la clase anónima, por ejemplo:
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);
}
... ¿y así?
El Lambda EG sí consideró este problema. Muchas bibliotecas usan interfaces funcionales, a pesar de que fueron diseñadas años antes de que la interfaz funcional se convirtiera en una cosa. Pero a veces sucede que una clase tiene múltiples métodos abstractos, y solo quieres apuntar a uno de ellos con un lambda.
El patrón recomendado oficialmente aquí es definir métodos de fábrica:
static MouseListener clickHandler(Consumer<MouseEvent> c) { return ... }
Esto se puede hacer directamente por las propias API (estos podrían ser métodos estáticos dentro de MouseListener
) o podrían ser métodos de ayuda externa en alguna otra biblioteca si los mantenedores eligen no ofrecer esta conveniencia. Debido a que el conjunto de situaciones en las que esto era necesario es pequeño, y la solución es tan simple, no parecía convincente extender el lenguaje aún más para rescatar este caso de esquina.
Un truco similar fue empleado para ThreadLocal
; vea el nuevo método de fábrica estático withInitial(Supplier<S>)
.
(Por cierto, cuando surge este problema, el ejemplo casi siempre es MouseListener
, lo cual es alentador, ya que sugiere que el conjunto de clases a las que les gustaría ser amigables con lambda, pero que no lo son, es realmente bastante pequeño).
No se puede acceder a los métodos predeterminados desde expresiones lambda. El siguiente código no se compila:
interface Formula {
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(a);
}
}
Formula formula = (a) -> sqrt( a * 100);
solo funciona con interfaz funcional (solo método abstracto único + cualquier número de métodos predeterminados) para que lambda expresion funcione solo con método abstracto
Puede usar interfaces multiproceso con lambdas utilizando interfaces auxiliares. Esto funciona con tales interfaces de escucha donde las implementaciones de métodos no deseados son triviales (es decir, podemos hacer lo que MouseAdapter
también ofrece):
// 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) {}
}
Necesita definir dicha interfaz de ayudante solo una vez.
Ahora puede agregar un oyente para eventos de clic en un Component
c
como este:
c.addMouseListener((ClickedListener)(e)->System.out.println("Clicked !"));
Un ActionListener
Java debe implementar un solo método ( actionPerformed(ActionEvent e)
). Esto encaja perfectamente en la function Java 8 function por lo que Java 8 proporciona una lambda simple para implementar un ActionListener
.
El MouseAdapter
requiere al menos dos métodos, por lo que no cabe como una function
.