Considero que final
en los parámetros del método y las variables locales es ruido de código. Las declaraciones de métodos de Java pueden ser bastante largas (especialmente con los genéricos), ya no es necesario hacerlas más.
Si las pruebas unitarias se escriben correctamente, se asignará a los parámetros que son "dañinos", por lo que nunca debería ser realmente un problema. La claridad visual es más importante que evitar un error posible que no se detecte porque las pruebas de unidad no tienen cobertura suficiente.
Herramientas como FindBugs y CheckStyle que pueden configurarse para dividir la compilación si la asignación se realiza a parámetros o variables locales, si te interesan profundamente esas cosas.
Por supuesto, si necesita para que sean definitivos, por ejemplo, porque está usando el valor en una clase anónima, entonces no hay problema, esa es la solución más simple y limpia.
Además del efecto obvio de agregar palabras clave adicionales a sus parámetros y, por lo tanto, IMHO camuflándolos, agregar parámetros finales al método a menudo puede hacer que el código en el cuerpo del método sea menos legible, lo que empeora el código: "bueno" ", el código debe ser lo más legible y simple posible. Para un ejemplo artificial, digamos que tengo un método que necesita trabajar con mayúsculas y minúsculas.
Sin final
:
public void doSomething(String input) {
input = input.toLowerCase();
// do a few things with input
}
Simple. Limpiar. Todo el mundo sabe lo que está pasando.
Ahora con 'final', opción 1:
public void doSomething(final String input) {
final String lowercaseInput = input.toLowerCase();
// do a few things with lowercaseInput
}
Mientras que hacer los parámetros final
impide que el codificador agregue el código más abajo al pensar que está trabajando con el valor original, existe el mismo riesgo de que el código más abajo pueda usar input
en lugar de lowercaseInput
, lo cual no debería y contra lo que no se puede proteger, porque no puedes sacarlo del alcance (o incluso asignar null
a input
si eso ayudaría de todos modos).
Con 'final', opción 2:
public void doSomething(final String input) {
// do a few things with input.toLowerCase()
}
Ahora acabamos de crear aún más ruido de código e introdujimos un golpe de rendimiento al tener que invocar toLowerCase()
n veces.
Con 'final', opción 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
}
Habla sobre el ruido del código. Esto es un choque de trenes. Tenemos un nuevo método, un bloque de excepción requerido, porque otro código puede invocarlo incorrectamente. Más pruebas unitarias para cubrir la excepción. Todo para evitar una línea simple e IMHO preferible e inofensiva.
También existe el problema de que los métodos no deben ser tan largos que no se pueden captar visualmente fácilmente y saber de un vistazo que se ha realizado una asignación a un parámetro.
Creo que es una buena práctica / estilo que si asigna un parámetro lo hace al principio del método, preferiblemente en la primera línea o inmediatamente después de la verificación de entrada básica, reemplazándolo para la todo , que tiene un efecto consistente dentro del método. Los lectores saben que esperan que cualquier asignación sea obvia (cerca de la declaración de la firma) y en un lugar coherente, lo que mitiga en gran medida el problema que la adición final intenta evitar. En realidad, rara vez asigno parámetros, pero si lo hago, siempre lo hago en la parte superior de un método.
Tenga en cuenta también que final
en realidad no lo protege como parece a primera vista:
public void foo(final Date date) {
date.setTime(0);
// code that uses date
}
final
no lo protege completamente a menos que el tipo de parámetro sea primitivo o inmutable.