Declarar variables dentro o fuera de un bucle

Resuelto Harry Joy asked hace 12 años • 20 respuestas

¿Por qué lo siguiente funciona bien?

String str;
while (condition) {
    str = calculateStr();
    .....
}

Pero se dice que este es peligroso/incorrecto:

while (condition) {
    String str = calculateStr();
    .....
}

¿Es necesario declarar variables fuera del bucle?

Harry Joy avatar Jan 10 '12 20:01 Harry Joy
Aceptado

El alcance de las variables locales siempre debe ser el más pequeño posible.

En su ejemplo, supongo que nostr se usa fuera del bucle; de ​​lo contrario, no estaría haciendo la pregunta, porque declararlo dentro del bucle no sería una opción, ya que no se compilaría.whilewhile

Entonces, dado que nostr se usa fuera del ciclo, el alcance más pequeño posible está dentro del ciclo while.str

Entonces, la respuesta es enfáticamente que strabsolutamente debe declararse dentro del ciclo while. Sin peros ni peros.

El único caso en el que se podría violar esta regla es si por alguna razón es de vital importancia que cada ciclo de reloj deba eliminarse del código, en cuyo caso es posible que desee considerar crear una instancia de algo en un ámbito externo y reutilizarlo en lugar de volviendo a crear una instancia en cada iteración de un alcance interno. Sin embargo, esto no se aplica a su ejemplo, debido a la inmutabilidad de las cadenas en Java: siempre se creará una nueva instancia de str al comienzo de su ciclo y tendrá que desecharse al final del mismo, por lo que no No hay posibilidad de optimizar allí.

EDITAR: (inyectando mi comentario a continuación en la respuesta)

En cualquier caso, la forma correcta de hacer las cosas es escribir todo el código correctamente, establecer un requisito de rendimiento para su producto, medir su producto final con respecto a este requisito y, si no lo satisface, optimizar las cosas. Y lo que normalmente termina sucediendo es que encuentras formas de proporcionar algunas optimizaciones algorítmicas agradables y formales en solo un par de lugares que hacen que nuestro programa cumpla con sus requisitos de rendimiento en lugar de tener que revisar toda tu base de código y modificar y piratear cosas. para apretar los ciclos de reloj aquí y allá.

Mike Nakis avatar Jan 10 '2012 13:01 Mike Nakis

Comparé el código de bytes de esos dos ejemplos (similares):

Veamos 1. ejemplo :

package inside;

public class Test {
    public static void main(String[] args) {
        while(true){
            String str = String.valueOf(System.currentTimeMillis());
            System.out.println(str);
        }
    }
}

después javac Test.java, javap -c Testobtendrás:

public class inside.Test extends java.lang.Object{
public inside.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method java/lang/System.currentTimeMillis:()J
   3:   invokestatic    #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
   6:   astore_1
   7:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_1
   11:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    0

}

Veamos 2. ejemplo :

package outside;

public class Test {
    public static void main(String[] args) {
        String str;
        while(true){
            str =  String.valueOf(System.currentTimeMillis());
            System.out.println(str);
        }
    }
}

después javac Test.java, javap -c Testobtendrás:

public class outside.Test extends java.lang.Object{
public outside.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method java/lang/System.currentTimeMillis:()J
   3:   invokestatic    #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
   6:   astore_1
   7:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_1
   11:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    0

}

Las observaciones muestran que no hay diferencia entre esos dos ejemplos. Es el resultado de las especificaciones JVM...

Pero en nombre de las mejores prácticas de codificación, se recomienda declarar la variable en el alcance más pequeño posible (en este ejemplo, está dentro del bucle, ya que este es el único lugar donde se usa la variable).

PrimosK avatar Jan 16 '2012 09:01 PrimosK

Declarar objetos en el alcance más pequeño mejora la legibilidad .

El rendimiento no importa para los compiladores actuales (en este escenario).
Desde una perspectiva de mantenimiento, la segunda opción es mejor.
Declare e inicialice variables en el mismo lugar, en el ámbito más estrecho posible.

Como dijo Donald Ervin Knuth :

"Deberíamos olvidarnos de las pequeñas eficiencias, aproximadamente el 97% de las veces: la optimización prematura es la raíz de todos los males"

es decir, situación en la que un programador permite que las consideraciones de rendimiento afecten el diseño de un fragmento de código. Esto puede dar como resultado un diseño que no es tan limpio como podría haber sido o un código incorrecto, porque el código se complica por la optimización y el programador se distrae con la optimización .

Chandra Sekhar avatar Jan 21 '2012 20:01 Chandra Sekhar