O Java 8 adicionou o conceito de interfaces funcionais , bem como vários novos métodos projetados para assumir interfaces funcionais. Instâncias dessas interfaces podem ser criadas de forma sucinta usando expressões de referência de método (por exemplo SomeClass::someMethod
) e expressões lambda (por exemplo (x, y) -> x + y
).
Um colega e eu temos opiniões divergentes sobre quando é melhor usar um formulário ou outro (onde "melhor", neste caso, realmente se resume a "mais legível" e "mais alinhado às práticas padrão", pois é basicamente o contrário. equivalente). Especificamente, isso envolve o caso em que tudo a seguir é verdadeiro:
- a função em questão não é usada fora de um único escopo
- dar um nome à instância ajuda na legibilidade (em vez de, por exemplo, a lógica ser simples o suficiente para ver o que está acontecendo rapidamente)
- não há outras razões de programação pelas quais um formulário seja preferível ao outro.
Minha opinião atual sobre o assunto é que adicionar um método privado e referir isso por referência de método é a melhor abordagem. Parece que foi assim que o recurso foi projetado para ser usado, e parece mais fácil comunicar o que está acontecendo por meio de nomes e assinaturas de métodos (por exemplo, "booleano isResultInFuture (resultado do resultado)" está claramente dizendo que está retornando um booleano). Ele também torna o método privado mais reutilizável se um aprimoramento futuro da classe quiser fazer uso da mesma verificação, mas não precisar do wrapper da interface funcional.
A preferência do meu colega é ter um método que retorne a instância da interface (por exemplo, "Predicate resultInFuture ()"). Para mim, parece que não é exatamente como o recurso deveria ser usado, parece um pouco mais desajeitado e parece que é mais difícil realmente comunicar a intenção por meio de nomes.
Para tornar esse exemplo concreto, aqui está o mesmo código, escrito nos diferentes estilos:
public class ResultProcessor {
public void doSomethingImportant(List<Result> results) {
results.filter(this::isResultInFuture).forEach({ result ->
// Do something important with each future result line
});
}
private boolean isResultInFuture(Result result) {
someOtherService.getResultDateFromDatabase(result).after(new Date());
}
}
vs.
public class ResultProcessor {
public void doSomethingImportant(List<Result> results) {
results.filter(resultInFuture()).forEach({ result ->
// Do something important with each future result line
});
}
private Predicate<Result> resultInFuture() {
return result -> someOtherService.getResultDateFromDatabase(result).after(new Date());
}
}
vs.
public class ResultProcessor {
public void doSomethingImportant(List<Result> results) {
Predicate<Result> resultInFuture = result -> someOtherService.getResultDateFromDatabase(result).after(new Date());
results.filter(resultInFuture).forEach({ result ->
// Do something important with each future result line
});
}
}
Existe alguma documentação ou comentário oficial ou semioficial sobre se uma abordagem é mais preferida, mais alinhada com as intenções dos designers de idiomas ou mais legível? Salvo uma fonte oficial, existem razões claras pelas quais alguém seria a melhor abordagem?
Object::toString
). Portanto, minha pergunta é mais sobre se é melhor nesse tipo específico de instância que estou apresentando aqui do que se existem casos em que um é melhor que o outro ou vice-versa.