Eu considero final
nos parâmetros do método e variáveis locais como ruído de código. Declarações de método Java podem ser bastante longas (especialmente com genéricos) - não há necessidade de torná-las mais longas.
Se os testes de unidade forem escritos corretamente, a atribuição a parâmetros que são "prejudiciais" será selecionada, portanto, isso nunca deve ser realmente um problema. A clareza visual é mais importante do que evitar um bug possível que não foi detectado porque os testes de unidade têm cobertura insuficiente.
Ferramentas como FindBugs e CheckStyle que podem ser configuradas para quebrar a compilação se a atribuição for feita para parâmetros ou variáveis locais, se você se importa profundamente com essas coisas.
Claro, se você precisar para torná-los finais, por exemplo, porque você está usando o valor em uma classe anônima, então não há problema - essa é a solução mais simples e simples.
Além do efeito óbvio de adicionar palavras-chave extras aos seus parâmetros e, portanto, IMHO camuflá-los, adicionar parâmetros finais ao método pode frequentemente tornar o código no corpo do método menos legível, o que torna o código pior - ser "bom" ", o código deve ser tão legível e tão simples quanto possível. Para um exemplo artificial, digamos que eu tenha um método que precise trabalhar insensivelmente em maiúsculas e minúsculas.
Sem final
:
public void doSomething(String input) {
input = input.toLowerCase();
// do a few things with input
}
Simples. Limpar \ limpo. Todo mundo sabe o que está acontecendo.
Agora com 'final', opção 1:
public void doSomething(final String input) {
final String lowercaseInput = input.toLowerCase();
// do a few things with lowercaseInput
}
Ao fazer os parâmetros final
pararem o codificador adicionando código mais abaixo ao pensar que ele está trabalhando com o valor original, há um risco igual de que o código mais baixo use input
em vez de lowercaseInput
, o que não deveria e que não podem ser protegidos, porque você não pode tirá-lo do escopo (ou até mesmo atribuir null
a input
se isso puder ajudar mesmo assim).
Com 'final', opção 2:
public void doSomething(final String input) {
// do a few things with input.toLowerCase()
}
Agora, acabamos de criar ainda mais ruídos de código e introduzimos um impacto no desempenho de ter que invocar toLowerCase()
n vezes.
Com 'final', opção 3:
public void doSomething(final String input) {
doSomethingPrivate(input.toLowerCase());
}
/** @throws IllegalArgumentException if input not all lower case */
private void doSomethingPrivate(final String input) {
if (!input.equals(input.toLowerCase())) {
throw new IllegalArgumentException("input not lowercase");
}
// do a few things with input
}
Fale sobre o ruído do código. Este é um acidente de trem. Temos um novo método, um bloco de exceção obrigatório, porque outro código pode invocá-lo incorretamente. Mais testes de unidade para cobrir a exceção. Tudo para evitar uma linha simples, e IMHO preferível e inofensiva.
Há também o problema de que os métodos não devem ser tão longos que você não consiga visualizá-los com facilidade e saber de imediato que uma atribuição ao parâmetro ocorreu.
Eu acho que é uma boa prática / estilo que se você atribuir a um parâmetro você o faça no início do método, de preferência na primeira linha ou diretamente após a verificação básica de entrada, efetivamente substituindo para o parâmetro método inteiro , que tem um efeito consistente dentro do método. Os leitores sabem esperar que qualquer atribuição seja óbvia (perto da declaração da assinatura) e em um local consistente, o que mitiga bastante o problema que a adição final está tentando evitar. Na verdade, raramente atribuo parâmetros, mas, se o faço, sempre faço isso no topo de um método.
Note também que final
na verdade não protege você da maneira que parece:
public void foo(final Date date) {
date.setTime(0);
// code that uses date
}
final
não protege você completamente, a menos que o tipo de parâmetro seja primitivo ou imutável.