Vamos considerar uma situação em que uma classe substitui um método da sua superclasse e deseja consultar a versão do método da superclasse usando uma referência de método:
class Base {
public void show() {
System.out.println("Base class show method.");
}
}
public class Derived extends Base {
@Override
public void show() {
System.out.println("Derived class show method.");
}
public void performShow(Runnable action) {
action.run();
}
public void executeShow() {
// Using 'super' with method reference to refer to the superclass's method
performShow(super::show);
}
public static void main(String() args) {
new Derived().executeShow();
}
}
Neste exemplo:
super::show
é uma referência de método que aponta para oshow
Método da superclasseBase
Da subclasseDerived
.- O método
executeShow
Usa essa referência de método para garantir que o método da superclasse seja usado, mesmo que seja substituído na classe atual.
Aplicações práticas de referências de método
Você pode usar referências de método sempre que as interfaces funcionais são aplicáveis. Eles são particularmente úteis em operações de fluxo, configurações de ouvintes de eventos e cenários envolvendo métodos de interfaces de programação funcional como Function
Assim, Consumer
Assim, Predicate
e Supplier
. Aqui estão alguns exemplos:
- Operações de fluxo: Na API Java Streams, as referências de método são comumente usadas em
map
Assim,filter
Assim,forEach
e outras operações. Por exemplo,stream.map(String::toUpperCase)
Usa uma referência de método para transformar cada elemento de um fluxo em maiúsculas. - Ouvintes de eventos: Em aplicações da GUI ou programação orientada a eventos, as referências de método simplificam o anexo do comportamento aos eventos. Como exemplo,
button.addActionListener(this::methodName)
Liga o método diretamente como ouvinte de evento. - Construtores e fábricas: Ao usar fluxos Java e outras APIs que requerem geração de objetos, as referências do construtor fornecem uma abreviação para a criação de objetos, como
Stream.generate(ClassName::new)
.
Vantagens e desvantagens do uso de referências de método
As referências de método aprimoram o poder expressivo do Java, permitindo que os desenvolvedores escrevam mais programação de estilo funcional. Sua integração com os recursos existentes da Java, como fluxos e lambdas, ajuda os desenvolvedores a escrever código limpo e sustentável. Recursos como referências de método fazem parte da integração contínua de Java de padrões de programação funcional.
O uso de referências de método tem algumas vantagens:
- Legibilidade: O código escrito usando referências de método é mais claro e mais sucinto.
- Eficiência: Referências de método ajudam a reduzir o código da caldeira em comparação com as implementações tradicionais de classe anônima.
- Manutenção: As referências de método são mais fáceis do que os Lambdas para entender e modificar.
Embora as referências de método possam simplificar e esclarecer o código, elas também têm possíveis desvantagens que podem levar a um código menos sustentável:
- Uso excessivo em cenários complexos: Evite usar referências de método para métodos com operações complexas ou quando são necessárias transformações nos parâmetros antes da aplicação do método. Por exemplo, se um lambda envolve modificar parâmetros antes de uma chamada de método, substituí -lo por uma referência de método pode obscurecer o que está acontecendo, como em
stream.map(x -> process(x).save()) versus stream.map(MyClass::save)
. - Legibilidade reduzida: As referências de método não devem ser usadas se dificultarem seu código. Isso pode acontecer se o método que está sendo referenciado não for auto-explicativo ou envolver efeitos colaterais que não estão imediatamente claros no contexto de uso.
- Desafios de depuração: A depuração pode ser um pouco mais desafiadora com as referências de método, porque elas não fornecem tanto detalhes em linha quanto Lambdas. Quando algo dá errado, pode ser mais difícil identificar se uma referência de método estiver passando valores inesperados.
Ao manter em mente essas melhores práticas e armadilhas, os desenvolvedores podem efetivamente usar referências de método para escrever um código Java mais limpo e mais eficiente, evitando armadilhas comuns que possam levar a um código difícil de ler e manter.
As referências de método são melhores do que Lambdas?
As referências de método podem produzir melhor desempenho do que as expressões Lambda, especialmente em certos contextos. Aqui estão os pontos -chave a serem considerados sobre os benefícios de desempenho das referências de método:
- Despesas gerais de código reduzidas: Referências de método geralmente resultam em código mais limpo e mais conciso. Eles não exigem o código da caldeira que os lambdas podem (como a declaração explícita de parâmetros), que pode tornar o bytecode resultante um pouco mais eficiente. Essa redução na complexidade do código pode facilitar a otimização da máquina virtual Java, potencialmente levando a um melhor desempenho.
- Otimização da JVM: A JVM possui otimizações especificamente adaptadas para referências de método, como invocar
invokevirtual
ouinvokeinterface
diretamente sem a sobrecarga adicional do invólucro Lambda. Essas otimizações podem potencialmente tornar as referências de método mais rápidas ou pelo menos tão rápidas quanto as expressões Lambda equivalentes. - Reutilização de instâncias de referência de método: Diferentemente das expressões de lambda, as referências de método não capturam valores do contexto anexando, a menos que seja explicitamente exigido. Isso geralmente permite que a JVM cache e reutilize instâncias de referências de método de maneira mais eficaz das expressões Lambda, que podem capturar valores diferentes e, portanto, podem exigir instâncias separadas cada vez que forem criadas.
- Cenários específicos: A vantagem de desempenho das referências de método pode ser mais perceptível em cenários específicos em que o mesmo método é reutilizado várias vezes em um grande conjunto de dados, como em fluxos ou chamadas de método repetitivo dentro de loops. Nesses casos, a sobrecarga reduzida e os potenciais benefícios de cache podem contribuir para um melhor desempenho.
- O benchmarking é fundamental: Embora existam vantagens teóricas, o impacto real do desempenho pode variar dependendo do caso de uso específico, da complexidade da expressão lambda e da implementação da JVM. Geralmente, é uma boa prática comparar o desempenho se for um fator crítico.