Eu estou procurando uma maneira de passar um método por referência. Entendo que Java não passa métodos como parâmetros, no entanto, gostaria de obter uma alternativa.
Disseram-me que as interfaces são a alternativa para passar métodos como parâmetros, mas não entendo como uma interface pode atuar como método por referência. Se bem entendi, uma interface é simplesmente um conjunto abstrato de métodos que não estão definidos. Não quero enviar uma interface que precise ser definida todas as vezes, porque vários métodos diferentes podem chamar o mesmo método com os mesmos parâmetros.
O que eu gostaria de realizar é algo semelhante a isto:
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());
Respostas:
Edit : a partir do Java 8, as expressões lambda são uma boa solução, como outras respostas apontaram. A resposta abaixo foi escrita para Java 7 e versões anteriores ...
Dê uma olhada no padrão de comando .
Edit: como Pete Kirkham aponta , há outra maneira de fazer isso usando um Visitante . A abordagem do visitante é um pouco mais envolvida - todos os nós precisam estar cientes do visitante com um
acceptVisitor()
método - mas se você precisar percorrer um gráfico de objetos mais complexo, vale a pena examinar.fonte
No Java 8, agora você pode passar um método mais facilmente usando Expressões e referências de método Lambda . Primeiro, alguns antecedentes: uma interface funcional é uma interface que possui um e apenas um método abstrato, embora possa conter qualquer número de métodos padrão (novos no Java 8) e métodos estáticos. Uma expressão lambda pode implementar rapidamente o método abstrato, sem toda a sintaxe desnecessária necessária se você não usar uma expressão lambda.
Sem expressões lambda:
Com expressões lambda:
Aqui está um trecho do tutorial Java sobre Expressões Lambda :
Aqui está como você pode "passar um método" usando uma expressão lambda:
A classe
C
pode ser reduzida ainda mais com o uso de referências de métodos como:fonte
::
operador), não importa o que seja.a.changeThing(component)
pode ser alterado para qualquer instrução ou bloco de código desejado, desde que retorne nulo.Use o
java.lang.reflect.Method
objeto e chameinvoke
fonte
Desde o Java 8, há uma
Function<T, R>
interface ( docs ), que possui o métodoVocê pode usá-lo para passar funções como parâmetros para outras funções. T é o tipo de entrada da função, R é o tipo de retorno.
No seu exemplo, você precisa passar uma função que aceita o
Component
tipo como entrada e não retorna nada -Void
. Nesse caso,Function<T, R>
não é a melhor opção, pois não há caixa automática do tipo Void. A interface que você está procurando é chamadaConsumer<T>
( docs ) com o métodoSeria assim:
E você poderia chamá-lo usando referências de método:
Supondo que você definiu os métodos changeColor () e changeSize () na mesma classe.
Se o seu método aceitar mais de um parâmetro, você poderá usar
BiFunction<T, U, R>
- T e U sendo tipos de parâmetros de entrada e R sendo tipo de retorno. Também háBiConsumer<T, U>
(dois argumentos, nenhum tipo de retorno). Infelizmente para 3 ou mais parâmetros de entrada, você deve criar uma interface sozinho. Por exemplo:fonte
Primeiro defina uma interface com o método que você deseja passar como parâmetro
Implementar uma classe com o método
// Invoca assim
Isso permite que você passe o cmd como parâmetro e invoque a chamada de método definida na interface
fonte
Embora isso ainda não seja válido para o Java 7 e abaixo, acredito que devemos olhar para o futuro e, pelo menos, reconhecer as mudanças que virão em novas versões, como o Java 8.
Nomeadamente, esta nova versão traz lambdas e referências de método para Java (junto com novas APIs , que são outra solução válida para esse problema. Embora ainda exijam uma interface, nenhum novo objeto foi criado, e arquivos de classe extras não precisam poluir os diretórios de saída devido a diferentes manipulação pela JVM.
Ambos os tipos (referência lambda e método) requerem uma interface disponível com um único método cuja assinatura é usada:
Os nomes dos métodos não serão importantes daqui em diante. Onde um lambda é aceito, uma referência de método também é. Por exemplo, para usar nossa assinatura aqui:
Esta é apenas uma invocação simples de interface, até que o lambda 1 seja passado:
Isso produzirá:
As referências de método são semelhantes. Dado:
e principal:
a saída seria
real static method
. As referências de método podem ser estáticas, instâncias, não estáticas com instâncias arbitrárias e até construtores . Para o construtor, algo semelhanteClassName::new
seria usado.1 Isso não é considerado um lambda por alguns, pois tem efeitos colaterais. Ilustra, no entanto, o uso de um de uma maneira mais fácil de visualizar.
fonte
Na última vez que verifiquei, o Java não é capaz de fazer o que você quer; você precisa usar 'soluções alternativas' para contornar essas limitações. Na minha opinião, as interfaces SÃO uma alternativa, mas não uma boa alternativa. Talvez quem tenha lhe dito isso estava significando algo assim:
Com o qual você invocaria:
fonte
Se você não precisar desses métodos para retornar algo, poderá fazê-los retornar objetos Runnable.
Em seguida, use-o como:
fonte
Não encontrei nenhum exemplo explícito o suficiente para mim sobre como usar o
java.util.function.Function
método simples como função de parâmetro. Aqui está um exemplo simples:Basicamente, você tem um
Foo
objeto com um construtor padrão. Ummethod
que será chamado como um parâmetro doparametrisedMethod
qual é do tipoFunction<String, Foo>
.Function<String, Foo>
significa que a função usa aString
como parâmetro e retorna aFoo
.Foo::Method
corresponde a um lambda comox -> Foo.method(x);
parametrisedMethod(Foo::method)
poderia ser visto comox -> parametrisedMethod(Foo.method(x))
.apply("from a method")
é basicamente fazerparametrisedMethod(Foo.method("from a method"))
O qual retornará na saída:
O exemplo deve estar sendo executado como está; você pode tentar coisas mais complicadas das respostas acima com diferentes classes e interfaces.
fonte
Java tem um mecanismo para passar o nome e chamá-lo. Faz parte do mecanismo de reflexão. Sua função deve receber parâmetro adicional da classe Method.
fonte
Eu não sou um especialista em java, mas resolvo seu problema assim:
Eu defino o parâmetro na minha interface especial
Por fim, implementei o método getSearchText ao chamar o método de inicialização .
fonte
Use o padrão Observer (às vezes também chamado de padrão do Listener):
new ComponentDelegate()...
declara um tipo anônimo implementando a interface.fonte
Aqui está um exemplo básico:
Resultado:
fonte
Não encontrei aqui nenhuma solução que mostre como passar o método com parâmetros vinculados a ele como parâmetro de um método. Abaixo está um exemplo de como você pode passar um método com valores de parâmetro já vinculados a ele.
Outro exemplo mostra como passar um método que realmente retorna algo
fonte
Exemplo de solução com reflexão, o método passado deve ser público
fonte
Aprecio as respostas acima, mas fui capaz de atingir o mesmo comportamento usando o método abaixo; uma ideia emprestada de retornos de chamada Javascript. Estou aberto à correção, embora até agora seja bom (em produção).
A idéia é usar o tipo de retorno da função na assinatura, o que significa que o rendimento deve ser estático.
Abaixo está uma função que executa um processo com um tempo limite.
fonte