2010-04-21 11 views
13

En el siguiente:En un bucle java mejorado para, ¿es seguro asumir que la expresión que se va a bifurcar se evaluará solo una vez?

for (String deviceNetwork : deviceOrganizer.getNetworkTypes(deviceManufacturer)) { 
    // do something 
} 

¿Es seguro asumir que deviceOrganizer.getNetworkTypes (deviceManufacturer) serán llamados sólo una vez?

+3

Sinceramente espero que sí, de lo contrario tengo un montón de código para reescribir ... – skaffman

+0

posible duplicado de http://stackoverflow.com/questions/1618202/java-foreach-loop –

+3

@Pascal Thivent - Sí, pero mi título es mejor :) – morgancodes

Respuesta

18

Sí, absolutamente.

De section 14.14.2 of the spec:

Si el tipo de expresión es un subtipo de Iterable, entonces Sea I el tipo de la expresión Expression.iterator(). La mejorada para la declaración es equivalente a un básico para enunciado de la forma: (. Las ofertas alternativas con matrices)

for (I #i = Expression.iterator(); #i.hasNext();) { 
     VariableModifiersopt Type Identifier = #i.next(); 
    Statement 
} 

Nota cómo Expression sólo se menciona en la primera parte de la de expresión de bucle - por lo que solo se evalúa una vez.

7

Sí, darle una oportunidad:

public class ForLoop { 
    public static void main(String [] args) { 
     for(int i : testData()){ 
      System.out.println(i); 
     } 
    } 
    public static int[] testData() { 
     System.out.println("Test data invoked"); 
     return new int[]{1,2,3,4}; 
    } 
} 

Salida:

$ java ForLoop 
Test data invoked 
1 
2 
3 
4 
1

Para complementar lo que se ha dicho y compruebe que la especificación está haciendo lo que dice, vamos a ver el bytecode generado para la siguiente clase, que implementa los bucles de estilo antiguo y nuevo para recorrer una lista devuelta por una llamada a un método, getList():

public class Main { 
    static java.util.List getList() { return new java.util.ArrayList(); } 
    public static void main(String[] args) { 
     for (Object o : getList()) { 
      System.out.print(o); 
     } 
     for (java.util.Iterator itr = getList().iterator(); itr.hasNext();) { 
      Object o = itr.next(); System.out.print(o); 
     } 
    } 
} 

partes pertinentes de la salida:

0: invokestatic #4; //Method getList 
    3: invokeinterface #5, 1; //InterfaceMethod java/util/List.iterator 
    8: astore_1 
    9: aload_1 
    10: invokeinterface #6, 1; //InterfaceMethod java/util/Iterator.hasNext 
    15: ifeq 35 
    18: aload_1 
    19: invokeinterface #7, 1; //InterfaceMethod java/util/Iterator.next 
    24: astore_2 
    25: getstatic #8; //Field java/lang/System.out 
    28: aload_2 
    29: invokevirtual #9; //Method java/io/PrintStream.print 
    32: goto 9 
    35: invokestatic #4; //Method getList 
    38: invokeinterface #10, 1; //InterfaceMethod java/util/List.iterator 
    43: astore_1 
    44: aload_1 
    45: invokeinterface #6, 1; //InterfaceMethod java/util/Iterator.hasNext 
    50: ifeq 70 
    53: aload_1 
    54: invokeinterface #7, 1; //InterfaceMethod java/util/Iterator.next 
    59: astore_2 
    60: getstatic #8; //Field java/lang/System.out 
    63: aload_2 
    64: invokevirtual #9; //Method java/io/PrintStream.print 
    67: goto 44 
    70: return 

Esto muestra que el primer bucle (0 a 32) y el segundo (35-67) son idéntica.
El bytecode generado es exactamente el mismo.

+2

Oh hombre ... ¿** tenemos que ** mirar los códigos byte? ¿No podemos pasar por lo que especifica el JLS? –

+0

LOL gracias Stephen, exactamente lo que estaba pensando. No para criticar al OP, pero en mi opinión bytecode no puede ayudarlo en esta instancia –

Cuestiones relacionadas