Estoy buscando una manera de pasar un método por referencia. Entiendo que Java no pasa los métodos como parámetros, sin embargo, me gustaría obtener una alternativa.
Me han dicho que las interfaces son la alternativa a pasar métodos como parámetros, pero no entiendo cómo una interfaz puede actuar como método por referencia. Si entiendo correctamente, una interfaz es simplemente un conjunto abstracto de métodos que no están definidos. No quiero enviar una interfaz que deba definirse cada vez porque varios métodos diferentes podrían llamar al mismo método con los mismos parámetros.
Lo que me gustaría lograr es algo similar a esto:
public void setAllComponents(Component[] myComponentArray, Method myMethod) {
for (Component leaf : myComponentArray) {
if (leaf instanceof Container) { //recursive call if Container
Container node = (Container) leaf;
setAllComponents(node.getComponents(), myMethod);
} //end if node
myMethod(leaf);
} //end looping through components
}
invocado como:
setAllComponents(this.getComponents(), changeColor());
setAllComponents(this.getComponents(), changeSize());
Respuestas:
Editar : a partir de Java 8, las expresiones lambda son una buena solución, como han señalado otras respuestas . La respuesta a continuación fue escrita para Java 7 y versiones anteriores ...
Echa un vistazo al patrón de comando .
Editar: como señala Pete Kirkham , hay otra forma de hacerlo usando un visitante . El enfoque del visitante es un poco más complicado: todos sus nodos deben ser conscientes del visitante con un
acceptVisitor()
método, pero si necesita atravesar un gráfico de objeto más complejo, vale la pena examinarlo.fuente
En Java 8, ahora puede pasar un método más fácilmente usando Expresiones de Lambda y Referencias de métodos. Primero, algunos antecedentes: una interfaz funcional es una interfaz que tiene un único método abstracto, aunque puede contener cualquier cantidad de métodos predeterminados (nuevos en Java 8) y métodos estáticos. Una expresión lambda puede implementar rápidamente el método abstracto, sin toda la sintaxis innecesaria necesaria si no utiliza una expresión lambda.
Sin expresiones lambda:
Con expresiones lambda:
Aquí hay un extracto del tutorial de Java sobre las expresiones Lambda :
Así es como puede "pasar un método" usando una expresión lambda:
La clase
C
se puede acortar incluso un poco más mediante el uso de referencias de métodos como esta:fuente
::
operador), no importa qué sea A.a.changeThing(component)
puede cambiarse a cualquier declaración o bloque de código que desee, siempre que devuelva nulo.Usa el
java.lang.reflect.Method
objeto y llamainvoke
fuente
Desde Java 8 hay una
Function<T, R>
interfaz ( docs ), que tiene un métodoPuede usarlo para pasar funciones como parámetros a otras funciones. T es el tipo de entrada de la función, R es el tipo de retorno.
En su ejemplo, debe pasar una función que tome el
Component
tipo como entrada y no devuelva nadaVoid
. En este casoFunction<T, R>
no es la mejor opción, ya que no hay autoboxing de tipo Void. La interfaz que está buscando se llamaConsumer<T>
( docs ) con métodoSe vería así:
Y lo llamarías usando referencias de método:
Suponiendo que haya definido los métodos changeColor () y changeSize () en la misma clase.
Si su método acepta más de un parámetro, puede usar
BiFunction<T, U, R>
: T y U son tipos de parámetros de entrada y R son tipos de retorno. También hayBiConsumer<T, U>
(dos argumentos, sin tipo de retorno). Desafortunadamente para 3 y más parámetros de entrada, debe crear una interfaz usted mismo. Por ejemplo:fuente
Primero defina una interfaz con el método que desea pasar como parámetro
Implementar una clase con el método.
// Invocar así
Esto le permite pasar cmd como parámetro e invocar la llamada al método definida en la interfaz
fuente
Si bien esto aún no es válido para Java 7 y versiones posteriores, creo que deberíamos mirar hacia el futuro y al menos reconocer los cambios que vendrán en nuevas versiones como Java 8.
Es decir, esta nueva versión trae referencias lambdas y de métodos a Java (junto con nuevas API , que son otra solución válida para este problema. Si bien aún requieren una interfaz, no se crean nuevos objetos, y los archivos de clase adicionales no necesitan contaminar directorios de salida debido a diferentes manejo por parte de la JVM.
Ambos sabores (referencia lambda y método) requieren una interfaz disponible con un único método cuya firma se utilice:
Los nombres de los métodos no serán importantes de aquí en adelante. Cuando se acepta una lambda, también se hace referencia a un método. Por ejemplo, para usar nuestra firma aquí:
Esta es solo una invocación de interfaz simple, hasta que se pasa la lambda 1 :
Esto generará:
Las referencias de métodos son similares. Dado:
y principal:
la salida sería
real static method
. Las referencias de métodos pueden ser estáticas, de instancia, no estáticas con instancias arbitrarias e incluso constructores . Para el constructor seClassName::new
usaría algo parecido .1 Algunos no lo consideran una lambda, ya que tiene efectos secundarios. Sin embargo, ilustra el uso de uno de una manera más sencilla de visualizar.
fuente
La última vez que lo revisé, Java no es capaz de hacer de forma nativa lo que quieres; tienes que usar 'soluciones alternativas' para sortear tales limitaciones. Por lo que yo veo, las interfaces SON una alternativa, pero no una buena alternativa. Quizás quien te dijo que significaba algo como esto:
Que luego invocarías con:
fuente
Si no necesita estos métodos para devolver algo, puede hacer que devuelvan objetos Runnable.
Luego úsalo como:
fuente
No encontré ningún ejemplo lo suficientemente explícito para mí sobre cómo usar
java.util.function.Function
un método simple como función de parámetro. Aquí hay un ejemplo simple:Básicamente tiene un
Foo
objeto con un constructor predeterminado. Amethod
que se llamará como un parámetro delparametrisedMethod
cual es de tipoFunction<String, Foo>
.Function<String, Foo>
significa que la función toma unString
parámetro y devuelve aFoo
.Foo::Method
corresponde a una lambda comox -> Foo.method(x);
parametrisedMethod(Foo::method)
podría ser visto comox -> parametrisedMethod(Foo.method(x))
.apply("from a method")
es básicamente hacerparametrisedMethod(Foo.method("from a method"))
Que luego regresará en la salida:
El ejemplo debería ejecutarse tal cual, luego puede probar cosas más complicadas de las respuestas anteriores con diferentes clases e interfaces.
fuente
Java tiene un mecanismo para pasar el nombre y llamarlo. Es parte del mecanismo de reflexión. Su función debe tomar parámetros adicionales de la clase Método.
fuente
No soy un experto en Java, pero resuelvo tu problema así:
Defino el parámetro en mi interfaz especial
Finalmente, implemento el método getSearchText mientras llamo al método initialize .
fuente
Utilice el patrón de observador (a veces también llamado patrón de escucha):
new ComponentDelegate()...
declara un tipo anónimo que implementa la interfaz.fuente
Aquí hay un ejemplo básico:
Salida:
fuente
No encontré ninguna solución aquí que muestre cómo pasar el método con parámetros vinculados a él como parámetro de un método. A continuación se muestra un ejemplo de cómo puede pasar un método con valores de parámetros ya vinculados a él.
Otro ejemplo muestra cómo pasar un método que realmente devuelve algo
fuente
Ejemplo de solución con reflexión, el método aprobado debe ser público
fuente
Agradezco las respuestas anteriores, pero pude lograr el mismo comportamiento utilizando el método a continuación; Una idea tomada de las devoluciones de llamada de Javascript. Estoy abierto a la corrección, aunque hasta ahora todo bien (en producción).
La idea es utilizar el tipo de retorno de la función en la firma, lo que significa que el rendimiento debe ser estático.
A continuación se muestra una función que ejecuta un proceso con un tiempo de espera.
fuente