Considere el siguiente código:
Stream<Integer> stream = Stream.of(1,2,3,4); int max = stream.max(Math::max).get(); System.out.println(max); |
Según el Javadoc de Steam.max (), el argumento del método max () debería ser un Comparador. En el código anterior, la referencia del método es a métodos estáticos de la clase Math. Pero el código se compila sin ningún mensaje de advertencia o error.
Entonces, ¿por qué es Math::max
aceptable mientras que aparentemente no es un Comparador?
La razón por la que se compila el código anterior está en el modo en que funciona la nueva funcionalidad lambda en Java 8. Se basa en un concepto que se conoce informalmente como interfaces de «método abstracto único (SAM)». La idea básica es que cualquier interfaz con un método abstracto puede ser implementada automáticamente por cualquier referencia de método o lambda, si la referencia de método o lambda coincide con el SAM en la interfaz.
Si echamos un vistazo a la interfaz de funciones Comparator
[1], su método abstracto único se parece a lo siguiente:
public Comparator<T> { int compare(T o1, T o2); } |
Si un método (max () en este caso) está buscando un Comparador
int xxx(Integer o1, Integer o2); |
«xxx» significa que el nombre del método no se utiliza con fines de coincidencia. El método Math.max () tiene la siguiente firma:
int max(int i1, int i2); |
Autoboxing permite que esto aparezca como un comparadorMath::max
es aceptado. Del mismo modo, también es aceptable un montón de otros métodos, como Integer::max
, Integer::min
, Math::min
etc.
El resultado será incorrecto. En lugar de, Integer::compare
debe usarse como el siguiente:
max = stream.max(Integer::compare).get(); System.out.println(max); |
Referencias:
[1]. Javadoc de Comparator en Java 8
[2]. Esta pregunta también es publicada por Fge de Desbordamiento de pila. La respuesta más popular es publicada por David Lloyd.