¿Hay alguna diferencia si declaro variables dentro o fuera de un bucle en Java? [cerrado]

13

Posible duplicado:
¿Dónde declaras las variables? ¿La parte superior de un método o cuando los necesita?

¿Hay alguna diferencia si declaro variables dentro o fuera de un bucle en Java?

Es esto

for(int i = 0; i < 1000; i++) {
   int temp = doSomething();
   someMethod(temp);
}

igual a esto (con respecto al uso de memoria)?

int temp = 0;
for(int i = 0; i < 1000; i++) {
   temp = doSomething();
   someMethod(temp);
}

¿Y si la variable temporal es, por ejemplo, una ArrayList?

for(int i = 0; i < 1000; i++) {
   ArrayList<Integer> array = new ArrayList<Integer>();
   fillArray(array);
   // do something with the array
}

EDITAR: javap -cobtuve el siguiente resultado

Variable fuera del ciclo:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iconst_0      
       3: istore_2      
       4: iload_2       
       5: sipush        1000
       8: if_icmpge     25
      11: invokestatic  #2                  // Method doSomething:()I
      14: istore_1      
      15: iload_1       
      16: invokestatic  #3                  // Method someMethod:(I)V
      19: iinc          2, 1
      22: goto          4
      25: return  

Variable dentro del bucle:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: sipush        1000
       6: if_icmpge     23
       9: invokestatic  #2                  // Method doSomething:()I
      12: istore_2      
      13: iload_2       
      14: invokestatic  #3                  // Method someMethod:(I)V
      17: iinc          1, 1
      20: goto          2
      23: return        

Y para los interesados, este código:

public class Test3 {
    public static void main(String[] args) {
        for(int i = 0; i< 1000; i++) {
            someMethod(doSomething());
        }   
    }
    private static int doSomething() {
        return 1;
    }
    private static void someMethod(int temp) {
        temp++;
    }
}

produce esto:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: sipush        1000
       6: if_icmpge     21
       9: invokestatic  #2                  // Method doSomething:()I
      12: invokestatic  #3                  // Method someMethod:(I)V
      15: iinc          1, 1
      18: goto          2
      21: return   

Pero la optimización ocurre en tiempo de ejecución entonces. ¿Hay alguna manera de ver el código optimizado? (Perdón por la larga edición)

Puckl
fuente
1
Me alegra que hayas visto el desmontaje y espero que te haya enseñado algo. Esperaba que alguien con experiencia real en Java respondiera su pregunta final sobre el código optimizado, pero tal vez pueda publicar esa parte específica en Stackoverflow; parece ser una pregunta muy concreta.
Joris Timmermans
Sí, intentaré obtener el código optimizado. (La pregunta cambió un poco, pregunté la cosa con el código optimizado en la edición)
Puckl
Enlace roto en duplicado. Es hora de hacer de esta pregunta un Original.
Zon

Respuestas:

4

La respuesta común a la mayoría de estas preguntas debería ser "¿por qué no lo prueba y lo descubre?". En Java, probablemente podría echar un vistazo al código de bytes generado (creo que la herramienta se llama javap), para ver cuál es la diferencia en el código de bytes entre esas dos formas de declarar la variable.

Hacerlo así es una mejor experiencia de aprendizaje para usted, porque la próxima vez que se encuentre con un problema de optimización puede usar la misma herramienta para verificar que el compilador está haciendo lo que espera: le ayudará a evitar cambiar innecesariamente su codificación estilo cuando el optimizador funciona bien por sí solo, o encuentra ajustes reales cuando realmente necesita ese último bit de rendimiento.

Joris Timmermans
fuente
3

Respuesta corta: no. Ya había preguntas similares en algún lugar de este sitio. No hay una diferencia notable según el bytecode generado. Declararlos cuando sea necesario produce menos líneas de código

Aquí está la respuesta aceptada: /software//a/56590/43451

Kemoda
fuente
¿Qué pasa con el rendimiento cuando crea un nuevo objeto dentro del bucle, que podría crearse solo una vez?
Bubblewrap
3
En este caso, obviamente, hay rendimiento y penalización de memoria. Pero no es exactamente el caso en la pregunta del
operador
1
El enlace está roto.
Zon
1

A nivel de la variable individual no hay una diferencia significativa en la eficiencia, pero si tuviera una función con 1000 bucles y 1000 variables (no importa el mal estilo implícito) podría haber diferencias sistémicas porque todas las vidas de todas las variables serían lo mismo en lugar de superponerse. Esto podría afectar cosas como el tamaño de la pila y la capacidad del recolector de basura para limpiar las variables que se mantuvieron con vida más tiempo del necesario.

Además, es mucho mejor estilo darles a las variables el alcance más pequeño posible. Previene accidentes.

ddyer
fuente
Esto no es cierto: en el nivel JVM, no existe un alcance limitado para las variables locales.
Michael Borgwardt
¿Quiere decir que si escribo para (int i = ..) 1000 veces, habrá 1000 variables diferentes en la pila cuando salga de la función?
ddyer
según artima.com/insidejvm/ed2/jvm8.html "Por ejemplo, si dos variables locales tienen ámbitos limitados que no se superponen, como las variables locales i y j en el Ejemplo 3b, los compiladores pueden usar la misma entrada de matriz para ambas variables ". Y eso solo tiene sentido, los compiladores son libres de optimizar el tamaño del marco de la pila de esta manera.
ddyer
1
Buen punto; pero si hablamos de optimizaciones del compilador, el compilador puede reutilizar casi tan fácilmente las entradas de variables locales para las variables que tienen un alcance léxico superpuesto pero que no se usan de manera superpuesta.
Michael Borgwardt