Hablando de programación funcional

  1. Conozca la interfaz funcional

Primero introduzca la interfaz funcional. Una interfaz funcional es una interfaz que tiene un solo método abstracto (puede haber varios métodos no abstractos). Las interfaces funcionales comunes incluyen Runnable, Comparable, etc.

@FunctionalInterface
public interface Runnable {
    
    
    void run();
}

public interface Comparable<T> {
    
    
    int compareTo(T var1);
}

Después de jdk1.8, se han agregado interfaces funcionales comunes (Función, Consumidor, Predicado, Proveedor, BiFunción, IntBinaryOperator) y sus interfaces funcionales derivadas en el paquete java.util.function.

public interface Consumer<T> {
    
    
    void accept(T var1);
}

public interface Function<T, R> {
    
    
    R apply(T var1);
}

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

public interface Supplier<T> {
    
    
    T get();
}

public interface BiFunction<T, U, R> {
    
    
    R apply(T var1, U var2);
}

public interface IntBinaryOperator {
    
    
    int applyAsInt(int var1, int var2);
}

Todas las interfaces funcionales anteriores usan genéricos, la diferencia radica en la firma del método. Por lo tanto, este artículo solo usa las dos primeras interfaces funcionales como ejemplos. Los otros principios son similares. Primero, tome la función como ejemplo:

public class FunctionClient {
    
    
    String clientPrint() {
    
    
        return "this is functionClient test";
    }

    public static void main(String[] args) {
    
    
        FunctionInterface functionInterface = new FunctionInterface();
        //第一种写法
        System.out.println(functionInterface.functionTest(FunctionClient::clientPrint));
        //第二种写法
        System.out.println((String) functionInterface.functionTest(functionClient -> functionClient.clientPrint()));
    }
}

class FunctionInterface {
    
    
    FunctionClient functionClient = new FunctionClient();
    <R> R functionTest(Function<FunctionClient, R> function) {
    
    
        return function.apply(functionClient);
    }
}

La interfaz funcional utilizada aquí es Function, que corresponde al método de aplicación. La FunctionTest en la clase FunctionalInterface se usa para simular la interfaz que los desarrolladores de SDK dan a los desarrolladores de software. El parámetro de entrada de esta interfaz es Function y el parámetro de salida es R :

<R> R functionTest(Function<FunctionClient, R> function) {
    
    
    return function.apply(functionClient);
}

Cuando el objeto de función llama al método de aplicación, en realidad ejecuta el código detrás de la flecha, que es functionClient.clientPrint (). El parámetro de entrada de functionTest es la expresión "functionClient -> functionClient.clientPrint ())". El tipo ejecutado en el lado derecho de la flecha es el tipo de valor de retorno de la interfaz funcional. Dado que functionClient.clientPrint () devuelve String, entonces aquí está R También se refiere específicamente al tipo String.

Además del objeto FunctionClient especificado anteriormente, ¿es posible usar tipos ordinarios en lugar de la clase FunctionClient en el lado izquierdo de la flecha?

public class FunctionClient {
    
    
    String clientPrint() {
    
    
        return "this is functionClient test";
    }

    public static void main(String[] args) {
    
    
        FunctionInterface functionInterface = new FunctionInterface();
        Function<String, String> function = "This is left param." -> new FunctionClient().clientPrint();//报错行
        System.out.println(functionInterface.functionTest(function));
    }
}

class FunctionInterface {
    
    
    <R> R functionTest(Function<String, R> function) {
    
    
        return function.apply("This is FunctionalInterface");
    }
}

El código anterior no se podrá compilar porque la función no puede aceptar el tipo de cadena y otras constantes. Dado que el lado izquierdo de la flecha representa el parámetro de entrada de un método, el parámetro de entrada solo puede ser una variable para el método, por lo que se informará un error si se define directamente como una constante.

Entonces, ¿cómo representar una escena sin parámetros? Simplemente defina una variable no declarada en el lado izquierdo de la flecha:

Function<String, String> function = s -> new FunctionClient().clientPrint();

Para la asignación de una interfaz funcional, el lado izquierdo de la flecha solo necesita pasar el número correspondiente de nombres de variables no asignados. Si no hay un parámetro de entrada, simplemente use ().

Si solo hay un valor de retorno y no hay parámetros, puede usar la interfaz del Proveedor:

public class FunctionClient {
    
    
    String clientPrint() {
    
    
        return "this is functionClient test";
    }

    public static void main(String[] args) {
    
    
        FunctionInterface functionInterface = new FunctionInterface();
        Supplier<String> function = () -> new FunctionClient().clientPrint();
        System.out.println(functionInterface.functionTest(function));
    }
}

class FunctionInterface {
    
    
    <R> R functionTest(Supplier<R> function) {
    
    
        return function.get();
    }
}
  1. ¿Cuáles son las ventajas de la programación funcional?

Simplifique el código, como:

Runnable runnable1 = new Runnable() {
    
    
    @Override
    public void run() {
    
    
        System.out.println("Runnable");
    }
};

//第一次简化,函数式编程(语句lambda形式)
Runnable runnable2 = () -> {
    
    
    System.out.println("Runnable");
};

//第二次简化,函数式编程(表达式lambda形式)
Runnable runnable3 = () -> System.out.println("Runnable");

又比如:

Consumer<Integer> consumer = i -> System.out.println(i);
List<Integer> arrayList = new ArrayList<>(){
    
    
    {
    
    
        add(1);
        add(2);
        add(4);
    }
};
arrayList.forEach(consumer);
  1. La relación entre lambda, programación funcional y devoluciones de llamada

1. Lambda es una implementación de una interfaz funcional, que puede entenderse como azúcar sintáctica.
2. La devolución de llamada no tiene límite en el número de métodos en la interfaz, pero las interfaces funcionales solo pueden especificar un método abstracto.
3. Las definiciones del método de programación funcional y devolución de llamada están en el llamador y las entradas de ambos son interfaces, pero una de ellas es una interfaz normal y la otra es una interfaz funcional.
4. La programación funcional y los métodos de devolución de llamada se ejecutan en el destinatario de la llamada. El primero ejecuta el único método correspondiente, como aplicar, mientras que el segundo puede corresponder a varios métodos, simplemente ejecute el método correspondiente.
5. Ambos pueden usar lambda para definir la implementación del método en el llamador.
6. La implementación de la programación funcional es una devolución de llamada especial.

Supongo que te gusta

Origin blog.csdn.net/weixin_48968045/article/details/113148594
Recomendado
Clasificación