"Punteros a métodos" en Java

Una de las cosas que extrañaba de C en Java es la capacidad de apuntar a una función. En lugar de invocar a una función directamente, podía hacerlo a través de una variable. Esto es: no importa a qué apunta a esa variable, cuando se invoca con los parámetros correctos, lo ejecutará.

En Java lo más cercano que se podía hacer era usando polimorfismo. A partir de Java 8 apareció lo que veremos en este post.



Consideremos este pequeño código en C.


Al ejecutarse esta es la salida:

La misma invocación, pero ejecuciones diferentes.

Si lo pensamos en Java, lo más parecido sería tener un método abstract (como de interface o de una clase abstracta) y dependiendo de su instanciación podremos tener el resultado diferente:



(Sí, mucho código para hacer lo mismo). La ejecución muestra el mismo resultado.

Ahora bien, se puede hasta reducir un poco más el código evitando crear las clases, solo implementamos la interfaz directamente:




Ya, tenemos menos código... pero aún estamos dependiendo de una interfaz. La cuestión es que, si quiero ejecutar un método que lo definí en alguna clase y no necesito crear una interfaz para ejecutar dependiendo de la implementación... ¿cómo lo hago?

Dos clases diferentes, dos métodos diferentes

Supongamos que tengamos dos clases, que en lo único que coinciden es un método que tienen la misma cantidad de parámetros. No tienen los mismos nombres, porque el diseño de mi aplicación funciona así (así que implementar una interfaz queda fuera). Estas clases son:




Ahora, vamos a instanciar esas dos clases, serán dos objetos diferentes. Pero queremos, por alguna razón de nuestra lógica, invocar a esos métodos, pero el que lo invoca no sabrá a quién está ejecutando.

Para poder implementar, debemos utilizar la interfaz Consumer, y le decimos cuál es el parámetro que va a tener:

    static void run(Consumer<Integer> c) {
        c.accept(10); //invoca el método, con el mismo parámetro
    }



Y, para ejecutarlo, debemos pasarle la variable seguido de un par de dos puntos :: y seguido el nombre del método:

Quiero obtener un valor

Hasta aquí fue un ejemplo invocando un método con un parámetro... pero ahora solo quiero invocar un método que me devuelva un valor. Vamos, tenemos estás clases:

Ahora bien, para ejecutar el método podría ser así:

    static String run(Supplier m) {
        return m.get(); //ejecuta el método cuando se le pasa
    }



Ahora bien, ejecutemos el código, le pasamos el método de la misma manera.

Pasar parámetro, obtener resultado

Ahora se pone interesante: pasarle un parámetro, y obtener un valor. Para eso usaremos Function

Nuestras clases a probar:



Ahora, ejecutaremos para ejecutar será:

    static String run(Function<String, String> f, String p) {
        return f.apply(p); //ejecuta la funcion con el parametro y lo devuelve
    }


y la ejecución será así:

Documentación

Para más detalle, revisar la documentación Package java.util.function

Comentarios

Entradas más populares de este blog

UML en NetBeans

Cambiar ícono a un JFrame

Portales en Java