Referências de método em Java
1. Visão geral
Uma das mudanças mais bem-vindas no Java 8 foi a introdução de https://www..com/java-8-lambda-expressions-tips [expressões lambda], pois elas permitem o abandono de classes anônimas, reduzindo bastante o código padrão e melhorar a legibilidade.
*As referências de método são um tipo especial de expressões lambda* . Eles geralmente são usados para criar expressões lambda simples fazendo referência a métodos existentes.
Existem quatro tipos de referências de método:
-
Métodos estáticos
-
Métodos de instância de objetos específicos
-
Métodos de instância de um objeto arbitrário de um tipo específico *Construtor
Neste tutorial, exploraremos as referências de método em Java.
2. Referência a um método estático
Começaremos com um exemplo muito simples, capitalizando e imprimindo uma lista de Strings:
List<String> messages = Arrays.asList("hello", "", "readers!");
Podemos conseguir isso utilizando uma expressão lambda simples chamada https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#capitalize-java.lang.String- Método [_StringUtils.capitalize () _] diretamente:
messages.forEach(word -> StringUtils.capitalize(word));
Ou, podemos usar uma referência de método para simplesmente nos referir ao método estático capitalize:
messages.forEach(StringUtils::capitalize);
- Observe que as referências de método sempre utilizam o operador _
-
_.
3. Referência a um método de instância de um objeto específico
Para demonstrar esse tipo de referência de método, vamos considerar duas classes:
public class Bicycle {
private String brand;
private Integer frameSize;
//standard constructor, getters and setters
}
public class BicycleComparator implements Comparator {
@Override
public int compare(Bicycle a, Bicycle b) {
return a.getFrameSize().compareTo(b.getFrameSize());
}
}
E, vamos criar um objeto BicycleComparator para comparar os tamanhos de quadros de bicicletas:
BicycleComparator bikeFrameSizeComparator = new BicycleComparator();
Poderíamos usar uma expressão lambda para classificar bicicletas por tamanho de quadro, mas precisaríamos especificar duas bicicletas para comparação:
createBicyclesList().stream()
.sorted((a, b) -> bikeFrameSizeComparator.compare(a, b));
Em vez disso, podemos usar uma referência de método para que o parâmetro do manipulador do compilador nos passe:
createBicyclesList().stream()
.sorted(bikeFrameSizeComparator::compare);
A referência do método é muito mais limpa e mais legível, pois nossa intenção é claramente mostrada pelo código.
4. Referência a um método de instância de um objeto arbitrário de um tipo particular
Esse tipo de referência de método é semelhante ao exemplo anterior, mas sem a necessidade de criar um objeto personalizado para realizar a comparação.
Vamos criar uma lista Integer que queremos classificar:
List<Integer> numbers = Arrays.asList(5, 3, 50, 24, 40, 2, 9, 18);
Se usarmos uma expressão lambda clássica, os dois parâmetros precisarão ser explicitamente transmitidos, enquanto o uso de uma referência de método é muito mais direto:
numbers.stream()
.sorted((a, b) -> a.compareTo(b));
numbers.stream()
.sorted(Integer::compareTo);
Mesmo sendo uma linha única, a referência do método é muito mais fácil de ler e entender.
5. Referência a um construtor
Podemos fazer referência a um construtor da mesma maneira que referenciamos um método estático em nosso primeiro exemplo. A única diferença é que usaremos a palavra-chave new.
Vamos criar uma matriz Bicycle a partir de uma lista String com marcas diferentes:
List<String> bikeBrands = Arrays.asList("Giant", "Scott", "Trek", "GT");
Primeiro, adicionaremos um novo construtor à nossa classe Bicycle:
public Bicycle(String brand) {
this.brand = brand;
this.frameSize = 0;
}
Em seguida, usaremos nosso novo construtor a partir de uma referência de método e criaremos uma matriz Bicycle a partir da lista String original:
bikeBrands.stream()
.map(Bicycle::new)
.toArray(Bicycle[]::new);
Observe como chamamos os construtores Bicycle e Array usando uma referência de método, dando ao nosso código uma aparência muito mais concisa e clara.
6. Exemplos e limitações adicionais
Como vimos até agora, as referências de métodos são uma ótima maneira de tornar nosso código e intenções muito claros e legíveis. No entanto, não podemos usá-los para substituir todos os tipos de expressões lambda, pois elas têm algumas limitações.
A principal limitação é o resultado da maior força:* a saída da expressão anterior precisa corresponder aos parâmetros de entrada da assinatura do método referenciado *.
Vamos ver um exemplo dessa limitação:
createBicyclesList().forEach(b -> System.out.printf(
"Bike brand is '%s' and frame size is '%d'%n",
b.getBrand(),
b.getFrameSize()));
Este caso simples não pode ser expresso com uma referência de método, porque o método printf requer 3 parâmetros em nosso caso, e o uso de createBicyclesList (). ForEach () _ só permitiria que a referência de método inferisse um parâmetro (o objeto _Bicycle).
Por fim, vamos explorar como criar uma função sem operação que pode ser referenciada a partir de uma expressão lambda.
Nesse caso, queremos usar uma expressão lambda sem usar seus parâmetros.
Primeiro, vamos criar o método doNothingAtAll:
private static <T> void doNothingAtAll(Object... o) {
}
Como é um método https://www..com/java-varargs [varargs], ele funcionará em qualquer expressão lambda, independentemente do objeto de referência ou do número de parâmetros inferidos.
Agora, vamos vê-lo em ação:
createBicyclesList()
.forEach((o) -> MethodReferenceExamples.doNothingAtAll(o));
7. Conclusão
Neste tutorial rápido, aprendemos quais referências de método existem em Java e como usá-las para substituir expressões lambda, melhorando a legibilidade e esclarecendo a intenção do programador.
Todo o código apresentado neste artigo está disponível over no GitHub.