Declarar variables dentro o fuera de un bucle
¿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?
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.while
while
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 str
absolutamente 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á.
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 Test
obtendrá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 Test
obtendrá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).
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 .