Esto puede ser algo común y trivial, pero parece que tengo problemas para encontrar una respuesta concreta. En C # hay un concepto de delegados, que se relaciona fuertemente con la idea de punteros de función de C ++. ¿Existe una funcionalidad similar en Java? Dado que los punteros están algo ausentes, ¿cuál es la mejor manera de hacerlo? Y para ser claros, estamos hablando de primera clase aquí.
java
pointers
delegates
function-pointers
grito de terror
fuente
fuente
this::myMethod
es semánticamente lo mismo que crear una lambdaparamA, paramB -> this.myMethod(paramA, paramB)
.Respuestas:
El lenguaje de Java para la funcionalidad de puntero de función es una clase anónima que implementa una interfaz, por ejemplo
Actualización: lo anterior es necesario en las versiones de Java anteriores a Java 8. Ahora tenemos alternativas mucho mejores, a saber, lambdas:
y referencias de métodos:
fuente
std::bind
, que une los parámetros a las funciones y devuelve un objeto invocable. No puedo defender C por estos motivos, pero C ++ es realmente mejor que Java para esto.Puede sustituir un puntero de función con una interfaz. Digamos que desea ejecutar una colección y hacer algo con cada elemento.
Esta es la interfaz que podríamos pasar a algunos, por ejemplo, CollectionUtils2.doFunc (Collection c, IFunction f).
Como ejemplo, digamos que tenemos una colección de números y le gustaría agregar 1 a cada elemento.
fuente
Puedes usar la reflexión para hacerlo.
Pase como parámetro el objeto y el nombre del método (como una cadena) y luego invoque el método. Por ejemplo:
Y luego úsalo como en:
Por supuesto, verifique todas las excepciones y agregue los moldes necesarios.
fuente
No, las funciones no son objetos de primera clase en Java. Puede hacer lo mismo implementando una clase de controlador: así es como se implementan las devoluciones de llamada en Swing, etc.
Sin embargo, hay propuestas de cierres (el nombre oficial de lo que estás hablando) en futuras versiones de Java: Javaworld tiene un artículo interesante.
fuente
Esto nos recuerda la Ejecución de Steve Yegge en el Reino de los sustantivos . Básicamente establece que Java necesita un objeto para cada acción y, por lo tanto, no tiene entidades "solo verbales" como punteros de función.
fuente
Para lograr una funcionalidad similar, puede usar clases internas anónimas.
Si tuviera que definir una interfaz
Foo
:Cree un método
bar
que recibirá un 'puntero de función' como argumento:Finalmente llame al método de la siguiente manera:
fuente
Java8 ha introducido lambdas y referencias de métodos . Entonces, si su función coincide con una interfaz funcional (puede crear la suya propia), puede usar una referencia de método en este caso.
Java proporciona un conjunto de interfaces funcionales comunes . mientras que podrías hacer lo siguiente:
fuente
alias
: por ejemplopublic List<T> collect(T t) = Collections::collect
No existe tal cosa en Java. Deberá ajustar su función en algún objeto y pasar la referencia a ese objeto para pasar la referencia al método en ese objeto.
Sintácticamente, esto se puede facilitar en cierta medida mediante el uso de clases anónimas definidas en el lugar o clases anónimas definidas como variables miembro de la clase.
Ejemplo:
fuente
He implementado el soporte de devolución de llamada / delegado en Java usando la reflexión. Los detalles y la fuente de trabajo están disponibles en mi sitio web .
Cómo funciona
Tenemos una clase principal llamada Callback con una clase anidada llamada WithParms. La API que necesita la devolución de llamada tomará un objeto de devolución de llamada como parámetro y, si es necesario, creará un Callback.WithParms como una variable de método. Dado que muchas de las aplicaciones de este objeto serán recursivas, esto funciona de manera muy limpia.
Dado que el rendimiento sigue siendo una gran prioridad para mí, no quería que se me pidiera que creara una matriz de objetos desechables para contener los parámetros para cada invocación; después de todo, en una estructura de datos grande podría haber miles de elementos y en un procesamiento de mensajes escenario podríamos terminar procesando miles de estructuras de datos por segundo.
Para ser seguro para subprocesos, la matriz de parámetros debe existir de manera única para cada invocación del método API, y para mayor eficacia, se debe usar el mismo para cada invocación de la devolución de llamada; Necesitaba un segundo objeto que sería barato de crear para vincular la devolución de llamada con una matriz de parámetros para la invocación. Pero, en algunos escenarios, el invocador ya tendría una matriz de parámetros por otros motivos. Por estas dos razones, la matriz de parámetros no pertenecía al objeto Callback. Además, la elección de la invocación (pasando los parámetros como una matriz o como objetos individuales) pertenece a la API utilizando la devolución de llamada que le permite utilizar la invocación que mejor se adapte a su funcionamiento interno.
La clase anidada WithParms, entonces, es opcional y tiene dos propósitos: contiene la matriz de objetos de parámetros necesarios para las invocaciones de devolución de llamada, y proporciona 10 métodos invoke () sobrecargados (con 1 a 10 parámetros) que cargan la matriz de parámetros y luego invocar el objetivo de devolución de llamada.
fuente
Compruebe los cierres cómo se han implementado en la biblioteca lambdaj. Realmente tienen un comportamiento muy similar al de los delegados de C #:
http://code.google.com/p/lambdaj/wiki/Closures
fuente
En relación con la mayoría de las personas aquí, soy nuevo en Java, pero como no he visto una sugerencia similar, tengo otra alternativa para sugerir. No estoy seguro de si es una buena práctica o no, o incluso sugerí antes y simplemente no lo entendí. Simplemente me gusta porque creo que es descriptivo.
luego, dependiendo de la aplicación, asigne
etc.
y llama por
fuente