Uso de "final" para parámetro de método en Java

Leí con interés esta pregunta: ¿Puedo pasar parámetros por referencia en Java?

Lo que resulta es que los parámetros (que no son primitivos) se pasan copiando el valor de referencia. Y así como dice el ejemplo; no puedes modificar la referencia del parámetro que diste:

Object o = "Hello";
mutate(o)
System.out.println(o); // Will print Hello

private void mutate(Object o) { o = "Goodbye"; } //NOT THE SAME o!

Este tipo de problema podría evitarse utilizando finalde esta manera:

private void mutate(final Object o) { o = "Goodbye"; } //Compilation error

Las preguntas :

  • Es el final palabra clave en tal caso solo se usa para generar un error de compilación?
  • Si al final no puede modificar la referencia del parámetro dado, ¿por qué no? final implícito u obligatorio?

Raramente usé final para los parámetros de método en Java, pero ahora no puedo pensar en ningún caso en el que omita voluntariamente poner final a un parámetro de método.

¡Gracias!

preguntado el 31 de julio de 12 a las 09:07

evita el uso de ese parámetro como una variable dentro del método, lo que facilita su lectura/comprensión:

Cuando crea una clase interna anónima dentro de un método, debe hacer que el parámetro sea como final para usarlo dentro de esa clase anónima. -

5 Respuestas

Para evitar esto:

public void searchBiggest(String startingWith) {
    for (String s : collection) {
        if (s.startsWith(startingWith)) {
            startingWith = s;
        }
    }
    return startingWith;
}

Como puede ver, hace que el código no sea intuitivo porque el parámetro podría tener un valor diferente al que pasó.

Desde Núcleo duro de Java - Capítulo 2:

Pequeños errores como este son a menudo los más difíciles de localizar. Según la Ley de Murphy, puede garantizar absolutamente que este código estará en el medio de una gran parte de su proyecto, y los informes de error no lo llevarán directamente aquí. Es más, probablemente no notará el impacto del error hasta que entre en producción y los usuarios estén pidiendo a gritos una solución.

No puede darse el lujo de olvidar que una vez que escribe el código, la historia no ha terminado. La gente hará cambios, adiciones y errores en su código. Tendrá que revisar el código y arreglar todo lo que estaba en mal estado. Para evitar que ocurra este problema, haga lo siguiente:

y se hace una muestra similar usando el parámetro, y adicionalmente invocando otros métodos con el parámetro (ya modificado).

Respondido 31 Jul 12, 10:07

Por lo general, no debe modificar los parámetros, ya que puede introducir errores difíciles de encontrar. Sin embargo, hay algunos modismos útiles y situaciones en las que puede ser útil:

public void print(String msg, int count) {
    msg = (msg != null)? msg : "Default";
    while(--count >= 0) {
        System.out.println(msg);
    }
}

Respondido 31 Jul 12, 10:07

Ok, definitivamente es solo para evitar crear una nueva variable en algunos casos. O tienes confianza en los otros desarrolladores y lo dejas así, o los obligas a ir con la variable temporal. - Michael Laffargue

Gracias a todos, me quedo con esta respuesta, ya que está más cerca de "¿Dónde no usar la final?". Otras respuestas me dieron los beneficios de final que ya sabía. - Michael Laffargue

Usualmente hago esto para prevenir accidentalmente o no intencionado modificaciones de esta referencia. p.ej

private String doSomething(final String arg) {
   // final to prevent me doing something stupid!
}

Un escenario interesante es el de los setters. Desea asegurarse de establecer la variable miembro y no el arg pasado en. p.ej

public void setArg(String arg) {
   _arg = arg;
}

En el escenario anterior, si el parámetro del método es no final, entonces posiblemente podría establecer

   arg = arg;

por error. Lo anterior es un error tipográfico común, o puede ocurrir debido a la refactorización de búsqueda/reemplazo. Haciendo arg final, no puede reasignarlo accidentalmente.

Respondido 31 Jul 12, 10:07

Estoy de acuerdo con eso, pero finalmente, ¿por qué alguien querría cambiar la referencia ya que solo se modificaría en el contexto del método? - Michael Laffargue

Ya vi códigos que usan el parámetro como una variable, hacen algo con el valor del parámetro, y luego simplemente lo anulan para usarlo en el método en sí: Francisco Spaeth

¿Posiblemente para evitar el dolor de declarar una nueva variable? ¡Es perezoso, pero a veces la gente hace cosas perezosas! - Brian Agnew

@BrianAgnew Lo hago siempre que puedo. - nulopotente

@AljoshaBre - ¿hacer qué? cosas perezosas? :-) Sí. Es mi práctica estándar. Ahora uso Scala, que tiene este comportamiento por defecto. - Brian Agnew

Java pasa por valor. Entonces, cuando llamas a mutate, se pasa una copia de o.

Dentro de mutate, la copia de o se configura para que apunte a "Adiós". La o original no cambia.

Establecer el parámetro para que sea final no cambiará esto, pero, como ha visto, detendrá la reasignación de la copia de la referencia original. Sin embargo, eso no es lo mismo que detener la reasignación de la referencia original.

Respondido 31 Jul 12, 10:07

1. Estas pasando el Object Reference Variable como el Argumento, cuando invocó el método llamándolo.

    mutate(o);

2. Mediante el uso de la final palabra clave en el Parameter en la definición del método, tienes lo hizo definitivo, entonces significa que Variable de referencia de objeto local o cual es de tipo El objeto es definitivo, asi que esta variable no se puede utilizar para señalar ningún otro objeto.

(Nota: Es el Object Reference Variable cual es final, No es el Objeto en el HEAP)

mutate(final Object o)

3. solicite asigne el objeto asociado con la variable de referencia de objeto o a alguna otra variable de referencia de objeto y luego cámbielo.

Object i = o;
 i = "GoodBye";

Respondido 31 Jul 12, 10:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.