Interfaces funcionales en Java

Java siempre ha sido un lenguaje de programación orientado a objetos. Por lenguaje de programación orientado a objetos, podemos declarar que todo lo presente en el lenguaje de programación Java rota a través de los Objetos, excepto algunos de los tipos de datos primitivos y métodos primitivos por integridad y simplicidad. No hay funciones únicas presentes en un lenguaje de programación llamado Java. Las funciones en el lenguaje de programación Java son parte de una clase, y si alguien quiere usarlas, tiene que usar la clase o el objeto de la clase para llamar a cualquier función.

Una interfaz funcional es una interfaz que contiene solo un método abstracto. Solo pueden tener una funcionalidad para exhibir. Desde Java 8 en adelante, las expresiones lambda se pueden usar para representar la instancia de una interfaz funcional. Una interfaz funcional puede tener cualquier número de métodos predeterminados. Runnable , ActionListener , Comparable son algunos de los ejemplos de interfaces funcionales. 

La interfaz funcional también se reconoce como interfaces de método abstracto único . En definitiva, también se les conoce como interfaces SAM . Las interfaces funcionales en Java son la nueva característica que brinda a los usuarios el enfoque de la programación fundamental. 

Las interfaces funcionales se incluyen en Java SE 8 con expresiones Lambda y referencias de métodos para que el código sea más legible, limpio y sencillo. Las interfaces funcionales son interfaces que aseguran que incluyen precisamente solo un método abstracto. Las interfaces funcionales se usan y ejecutan representando la interfaz con una anotación llamada @FunctionalInterface . Como se describió anteriormente, las interfaces funcionales pueden contener solo un método abstracto. Sin embargo, pueden incluir cualquier cantidad de métodos predeterminados y estáticos. 

En las interfaces funcionales, no hay necesidad de usar la palabra clave abstracta, ya que es opcional usar la palabra clave abstracta porque, de forma predeterminada, el método definido dentro de la interfaz es solo abstracto. También podemos llamar a las expresiones Lambda como la instancia de la interfaz funcional.

Antes de Java 8, teníamos que crear objetos de clase internos anónimos o implementar estas interfaces.

Java

// Java program to demonstrate functional interface
  
class Test {
    public static void main(String args[])
    {
        // create anonymous inner class object
        new Thread(new Runnable() {
            @Override public void run()
            {
                System.out.println("New thread created");
            }
        }).start();
    }
}
Producción

New thread created

Java 8 en adelante, podemos asignar la expresión lambda a su objeto de interfaz funcional de esta manera: 

Java

// Java program to demonstrate Implementation of
// functional interface using lambda expressions
  
class Test {
    public static void main(String args[])
    {
  
        // lambda expression to create the object
        new Thread(() -> {
            System.out.println("New thread created");
        }).start();
    }
}
Producción

New thread created

Anotación @FunctionalInterface 

La anotación @FunctionalInterface se usa para garantizar que la interfaz funcional no pueda tener más de un método abstracto. En caso de que haya más de un método abstracto presente, el compilador marca el mensaje ‘Anotación @FunctionalInterface inesperada’. Sin embargo, no es obligatorio utilizar esta anotación.

Java

// Java program to demonstrate lambda expressions to
// implement a user defined functional interface.
  
@FunctionalInterface
  
interface Square {
    int calculate(int x);
}
  
class Test {
    public static void main(String args[])
    {
        int a = 5;
  
        // lambda expression to define the calculate method
        Square s = (int x) -> x * x;
  
        // parameter passed and return type must be
        // same as defined in the prototype
        int ans = s.calculate(a);
        System.out.println(ans);
    }
}
Producción

25

Algunas interfaces funcionales de Java integradas

Desde Java SE 1.8 en adelante, hay muchas interfaces que se convierten en una interfaz funcional. Todas estas interfaces están anotadas con @FunctionalInterface. Estas interfaces son las siguientes: 

  • Ejecutable –> Esta interfaz solo contiene el método run().
  • Comparable -> Esta interfaz solo contiene el método compareTo().
  • ActionListener –> Esta interfaz solo contiene el método actionPerformed().
  • Invocable -> Esta interfaz solo contiene el método call().

Java SE 8 incluía cuatro tipos principales de interfaces funcionales que se pueden aplicar en múltiples situaciones. Estos son:

  1. Consumidor
  2. Predicado
  3. Función 
  4. Proveedor

En medio de las cuatro interfaces anteriores, las primeras tres interfaces, es decir, Consumidor, Predicado y Función, también tienen adiciones que se proporcionan a continuación: 

  1. Consumidor -> Bi-Consumidor
  2. Predicado -> Bi-Predicado
  3. Función -> Bi-Función, Operador Unario, Operador Binario 

1. Consumidor 

La interfaz de consumidor de la interfaz funcional es la que acepta un solo argumento o un argumento aburguesado. La interfaz de consumidor no tiene valor de retorno. No devuelve nada. También hay variantes funcionales del Consumidor: DoubleConsumer, IntConsumer y LongConsumer. Estas variantes aceptan valores primitivos como argumentos. 

Aparte de estas variantes, también hay una variante más de la interfaz del Consumidor conocida como Bi-Consumer. 

Bi-Consumer: Bi-Consumer es la variante más interesante de la interfaz Consumer. La interfaz del consumidor toma solo un argumento, pero por otro lado, la interfaz Bi-Consumer toma dos argumentos. Ambos, Consumidor y Bi-Consumidor no tienen valor de retorno. También regresa notando como la interfaz del Consumidor. Se utiliza para iterar a través de las entradas del mapa. 

Sintaxis / Prototipo de Interfaz Funcional de Consumidor – 

Consumer<Integer> consumer = (value) -> System.out.println(value);

Esta implementación de la interfaz funcional Java Consumer imprime el valor pasado como parámetro a la declaración de impresión. Esta implementación utiliza la función Lambda de Java.

2. Predicado 

En lógica científica, una función que acepta un argumento y, a cambio, genera un valor booleano como respuesta se conoce como predicado. De manera similar, en el lenguaje de programación java, una interfaz funcional de predicado de java es un tipo de función que acepta un solo valor o argumento y realiza algún tipo de procesamiento en él, y devuelve una respuesta booleana (Verdadero/Falso). La implementación de la interfaz funcional Predicate también encapsula la lógica de filtrado (un proceso que se utiliza para filtrar componentes de flujo sobre la base de un predicado proporcionado) en Java.

Al igual que la interfaz funcional del Consumidor, la interfaz funcional del Predicado también tiene algunas extensiones. Estos son IntPredicate, DoublePredicate y LongPredicate. Estos tipos de interfaces funcionales de predicado aceptan solo tipos de datos primitivos o valores como argumentos.  

Bi-Predicate: Bi-Predicate también es una extensión de la interfaz funcional de Predicate, que, en lugar de uno, toma dos argumentos, realiza algún procesamiento y devuelve el valor booleano.

Sintaxis de la interfaz funcional del predicado: 

public interface Predicate<T> {
 
    boolean test(T t);
 
}

La interfaz funcional de predicado también se puede implementar usando una clase. La sintaxis para la implementación de la interfaz funcional de predicado utilizando una clase se proporciona a continuación: 

public class CheckForNull implements Predicate {
 
    @Override
    public boolean test(Object o) {
 
        return o != null;
 
    }
}

La interfaz funcional de predicado de Java también se puede implementar mediante expresiones Lambda. El ejemplo de implementación de la interfaz funcional Predicate se proporciona a continuación: 

Predicate predicate = (value) -> value != null;

Esta implementación de interfaces funcionales en Java usando expresiones Java Lambda es más manejable y efectiva que la implementada usando una clase ya que ambas implementaciones están haciendo el mismo trabajo, es decir, devolviendo el mismo resultado.

3. Función  

Una función es un tipo de interfaz funcional en Java que recibe un solo argumento y devuelve un valor después del procesamiento requerido. Hay muchas versiones de interfaces de funciones porque un tipo primitivo no puede implicar un argumento de tipo general, por lo que necesitamos estas versiones de interfaces de funciones. Muchas versiones diferentes de las interfaces de función son instrumentales y se usan comúnmente en tipos primitivos como double, int, long. Las diferentes secuencias de estos tipos primitivos también se utilizan en el argumento.

Estas versiones son:

Bi-Función – La Bi-Función está sustancialmente relacionada con una Función. Además, toma dos argumentos, mientras que Function acepta un argumento. 

El prototipo y la sintaxis de Bi-Function se dan a continuación:

@FunctionalInterface
public interface BiFunction<T, U, R> 
{
 
   R apply(T t, U u);
    .......
 
}

En el código de interfaz anterior, T, U son las entradas y solo hay una salida que es R. 

Operador unario y Operador binario: también hay otras dos interfaces funcionales que se denominan Operador unario y Operador binario. Ambos amplían la Función y Bi-Función, respectivamente. En palabras simples, el operador unario amplía la función y el operador binario amplía la bifunción. 

El prototipo del Operador Unario y el Operador Binario se muestra a continuación:

1. Operador unario

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, U> 
{
    ……...
}

 2. Operador binario

@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T, U, R> 
{
    ……...
}

Podemos entender frente al ejemplo anterior que el operador unario acepta solo un argumento y devuelve un solo argumento. Aún así, en el operador unario, tanto los valores de entrada como los de salida deben ser idénticos y del mismo tipo. 

Por otro lado, el Operador Binario toma dos valores y devuelve un valor comparable a Bi-Función pero similar al Operador Unario, el tipo de valor de entrada y salida debe ser idéntico y del mismo tipo.

4. Proveedor 

La interfaz funcional del proveedor también es un tipo de interfaz funcional que no acepta ninguna entrada ni argumento y, sin embargo, devuelve una única salida. Este tipo de interfaz funcional se utiliza generalmente en la generación diferida de valores. Las interfaces funcionales del proveedor también se utilizan para definir la lógica para la generación de cualquier secuencia. Por ejemplo, la lógica detrás de la serie Fibonacci se puede generar con la ayuda del método Stream.generate, que se implementa mediante la interfaz funcional del proveedor. 

Las diferentes extensiones de la interfaz funcional del proveedor contienen muchas otras funciones del proveedor, como BooleanSupplier, DoubleSupplier, LongSupplier e IntSupplier. El tipo de retorno de todas estas especializaciones adicionales es solo sus primitivas correspondientes. 

La sintaxis/prototipo de la interfaz funcional del proveedor es:

@FunctionalInterface
public interface Supplier<T>{
 
// gets a result
………….
 
// returns the specific result
…………
 
T.get();
 
}

Java

// A simple program to demonstrate the use
// of predicate interface
  
import java.util.*;
import java.util.function.Predicate;
  
class Test {
    public static void main(String args[])
    {
  
        // create a list of strings
        List<String> names = Arrays.asList(
            "Geek", "GeeksQuiz", "g1", "QA", "Geek2");
  
        // declare the predicate type as string and use
        // lambda expression to create object
        Predicate<String> p = (s) -> s.startsWith("G");
  
        // Iterate through the list
        for (String st : names) {
            // call the test method
            if (p.test(st))
                System.out.println(st);
        }
    }
}
Producción

Geek
GeeksQuiz
Geek2

Puntos/observaciones importantes :

Aquí hay algunos puntos importantes con respecto a las interfaces funcionales en Java:

  1. En las interfaces funcionales, solo se admite un método abstracto. Si la anotación de una interfaz funcional, es decir, @FunctionalInterface no está implementada o escrita con una interfaz de función, se puede declarar más de un método abstracto dentro de ella. Sin embargo, en esta situación con más de una interfaz funcional, esa interfaz no se denominará interfaz funcional. Se llama una interfaz no funcional.
  2. No existe tal necesidad de la anotación @FunctionalInterface ya que es solo voluntaria. Esto está escrito porque ayuda a verificar el nivel del compilador. Además de esto, es opcional.
  3. Se puede agregar una cantidad infinita de métodos (ya sean estáticos o predeterminados) a la interfaz funcional. En palabras simples, no hay límite para una interfaz funcional que contenga métodos estáticos y predeterminados.
  4. La anulación de métodos de la clase principal no viola las reglas de una interfaz funcional en Java.
  5. El paquete java.util.function contiene muchas interfaces funcionales integradas en Java 8.

Este artículo es una contribución de Akash Ojha . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks. Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *