====== Interfaces funcionales, lambdas y referencias a métodos ======

==== Interfaces funcionales ====

  * Las interfaces funcionales son interfaces que poseen un único método abstracto (sin implementar)
  * Aparecen por primera vez en Java 8
  * Están especialmente preparadas para usarse con expresiones lambda
  * Pueden tener definidos métodos por defecto (tienen implementación)

En Java existen una serie de interfaces funcionales ya definidas especialmente útiles


  * **Predicate**: Evalua una condición booleana
    * //IntPredicate//, //LongPredicate//, //DoublePredicate//
  * **Consumer**: Acepta un input como entrada y no devuelve ningún resultado
    * //IntConsumer//, //LongConsumer//, //DoubleConsumer//
  * **Function**: Acepta un input como entrada y devuelve un resultado
    * //IntFunction//, //IntToDoubleFunction//, //IntToLongFunction//, //LongFunction//, LongToDoubleFunction, . . .
  * **Supplier**: No acepta argumentos y devuelve un resultado (al contrario que //Consumer//)
    * //BooleanSupplier//, //IntSupplier//, //LongSupplier//, //DoubleSupplier//
  * **BiPredicate**: Versión de //Predicat//e para dos argumentos
  * **BiFunction**: Versión de //Function// para dos argumentos

<code java>
Predicate<String> checkEmpty = (value) -> value.isEmpty();
System.out.println(checkEmpty.test("hola")); 
System.out.println(checkEmpty.test(""));
</code>

Pero también podemos crear las nuestras propias:

<code java>
@FunctionalInterface
public interface SayMyName {
  void say(String name); 
}
</code>





==== Expresiones lambda ====

  * Aparecen por primera vez en Java 8
  * Código más compacto y limpio
  * Sustituyen al concepto de clase anónima
  * Permiten expresar las instancias de interfaces funcionales de una forma compacta
  * Su uso está especialmente extendido en el uso de Streams, donde se pueden utilizar de forma que el código queda mucho más compacto y fácil de entender
  * Cuando usamos una tenemos que imaginarnos que estamos implementando el código necesario para ejecutar luego el método que tiene por defecto asignada esa interface

La sintaxis es:
<code java>
(parametros) -> (cuerpo-lambda)
</code>

Por ejemplo:

<code java>
// Para ordenar una lista
listaAnimales.sort((animal1, animal2) -> (animal1.getPeso() – animal2.getPeso());

// Para crear un Predicate que permita evaluar una colección sobre un objeto
Animal unAnimal = new Animal(. . . .)

Predicate<Animal> pesoMayorQue10 = (animal) -> animal.getPeso() > 10; 
pesoMayorQue10.test(unAnimal); // true/false
</code>

==== Referencias a métodos ====

Suponiendo que tenemos una colección de cadenas, veamos unos ejemplos que nos permitan utilizar una referencia a un método:

<code java>
List<String> cadenas = new ArrayList<>();
</code>

=== Métodos estáticos ===

<code java>
// Utilizando una expresión lambda
cadenas.forEach((cadena) -> System.out.println(cadena))
// Equivalente utilizando referencia a método
cadenas.forEach(System.out::println)
</code>

=== Métodos de instancia ===

<code java>
// Suponemos que existe una clase CadenasComparator que implementa Comparator
// Utilizando una expresión lambda
cadenas.sort((cadena1, cadena2) -> cadenasComparator.compare(cadena1, cadena2))
// Equivalente utilizando una referencia a método suponiendo que existe un objeto de la clase que implementa a CadenasComparator
cadenas.sort(cadenasComparator::compare);
// Equivalente utilizando una referencia a método
cadenas.sort(CadenasComparator::compare);
</code>

=== Constructores ===

<code java>
CadenasComparator::new
</code>

----

(c) 2019-{{date>%Y}} Santiago Faci