2010-01-05 19 views
8

Un dilema común que he enfrentado durante toda la programación es sobre declarar variables dentro de un bucle. Decir que tengo para llevar a cabo algo como lo siguiente:Declaración de variables dentro de un bucle

List list=myObject.getList(); 
Iterator itr=list.iterator(); 
while (itr.hasNext()){ 
    BusinessObject myBo=(BusinessObject)itr.next(); 
    process(myBo); 
} 

En el fragmento anterior, debe ser declarado myBo fuera del bucle o lo hace declarando que el interior del bucle no causa daño a la memoria y el rendimiento?

Respuesta

4

myBo es simplemente una referencia a un objeto (que es devuelto por itr.next()). Como tal, la cantidad de memoria que necesita es muy pequeña, y solo se crea una vez, y agregarla dentro del ciclo no debería afectar su programa. IMO, declararlo dentro del bucle donde se usa en realidad ayuda a hacerlo más legible.

+0

Esta respuesta es engañosa, ya que implica que la variable de referencia se asigna una vez por cada iteración, que es * no * verdadera. –

+0

@BlueRaja - Danny Pflughoeft: Como dije en mi respuesta, simplemente está creando una * referencia * a un objeto, no asignando todo el objeto en sí. Es por eso que la cantidad de memoria es muy pequeña, porque solo los pocos bytes necesarios para la referencia es todo lo que está involucrado. – MAK

+0

Sí, entiendo; pero incluso esa referencia (el puntero en sí) solo se asigna una vez, lo que es contrario a lo que la frase * "asignar/desasignar no debería afectar su programa significativamente" * implica. –

8

Declararlo dentro del bucle no causará ningún daño a la memoria y el rendimiento.

5

Si es posible utilizar List<BusinessObject> y Iterator<BusinessObject> para evitar la proyección de:

List<BusinessObject> list = myObject.getList(); 
Iterator<BusinessObject> itr = list.iterator(); 

while (itr.hasNext()) { 
    process(itr.next()); 
} 
+3

Por supuesto, solo funciona en 1.5 y superior. No todos son tan afortunados :) – extraneon

5

Uno de los principios del buen diseño de software es la de limitar el alcance de las variables locales, es decir, a los declaran justo a tiempo dentro de un bloque que termina poco después de el último uso de esa variable. Esto no afecta el rendimiento u otros aspectos "duros", pero hace que el programa sea más legible y más fácil de analizar.

En resumen, hacer lo que está haciendo se considera BUENO.

1

Si es corto - no. En C++ podría ser un problema si myBo se crea copiando , pero en Java siempre se usan referencias, ¿no es así?
para el rendimiento, es mejor para optimizar algo que se hace en proceso()

0

La referencia temporal myBo se pone en la pila y en su mayoría se deben optimizar distancia. No debe haber ninguna penalización de rendimiento en su código.

4

La solución más elegante para su bucle sería un bucle for mejorado (Java 5 o más reciente):

List<BusinessObject> list = myObject.getList(); 

for(BusinessObject myBo : list) { 
    process(myBo); 
} 

Pero incluso con el código que ya ha proporcionado no habrá ningún problema de rendimiento, ya que todas las variables temporales solo contiene referencias al BusinessObject, que es muy económico.

2

No causa ningún daño a la memoria.

Por cierto a menos que esté omitiendo algún código puede omitir por completo la declaración:

while (itr.hasNext()){ 
    //BusinessObject myBo=(BusinessObject)itr.next(); 
    process((BusinessObject)itr.next()); 
} 
1

Sólo echar un vistazo en el código de bytes con javap -c [ClassName]. Aquí hay una clase que muestra algunos ejemplos de variables de uso único con bucles. El volcado de código de bytes es relevante en los comentarios:

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

    void stringDeclaredInsideLoop(){ 
     while (true) { 
      // 0: ldC#2; //String Hello World! 
      String greeting = "Hello World!"; 
      doNothing(greeting); 
     } 
    } 
    // 
    // void stringDeclaredInsideLoop(); 
    // Code: 
    // 0: ldC#2; //String Hello World! 
    // 2: astore_1 
    // 3: aload_0 
    // 4: aload_1 
    // 5: invokespecial #3; //Method doNothing:(Ljava/lang/String;)V 
    // 8: goto 0 
    //////////////////////////////////////////////////////////////////////////// 

    void stringDeclaredOutsideLoop(){ 
     String greeting; 
     while (true) { 
      greeting = "Hello World!"; 
      doNothing(greeting); 
     } 
    } 
    // 
    // void stringDeclaredOutsideLoop(); 
    // Code: 
    // 0: ldC#2; //String Hello World! 
    // 2: astore_1 
    // 3: aload_0 
    // 4: aload_1 
    // 5: invokespecial #3; //Method doNothing:(Ljava/lang/String;)V 
    // 8: goto 0 
    //////////////////////////////////////////////////////////////////////////// 

    void stringAsDirectArgument(){ 
     while (true) { 
      doNothing("Hello World!"); 
     } 
    } 
    // void stringAsDirectArgument(); 
    // Code: 
    // 0: aload_0 
    // 1: ldC#2; //String Hello World! 
    // 3: invokespecial #3; //Method doNothing:(Ljava/lang/String;)V 
    // 6: goto 0 
    //////////////////////////////////////////////////////////////////////////// 

    private void doNothing(String s) { 
    } 
} 

stringDeclaredInsideLoop() y stringDeclaredOutsideLoop() rendimiento idéntico código de bytes de seis instrucción. stringDeclaredInsideLoop() todavía gana: alcance limitado es el mejor.

Después de un poco de contemplación, realmente no puedo ver cómo el alcance de ajuste podría afectar el rendimiento: datos idénticos en la pila necesitarían instrucciones idénticas.

stringAsDirectArgument(), sin embargo, define la operación en solo cuatro instrucciones. Los entornos con poca memoria (por ejemplo, mi teléfono magníficamente tonto) pueden apreciar la optimización, mientras que un colega que lee su código puede no hacerlo, así que tenga sentido antes de afeitar los bytes de su código.

Consulte el full gist para más.

Cuestiones relacionadas