2010-04-21 23 views
13

Trong điều sau đây:Trong java được tăng cường cho vòng lặp, có an toàn để giả sử biểu thức được lặp lại sẽ chỉ được đánh giá một lần?

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

Có an toàn để giả định rằng deviceOrganizer.getNetworkTypes (deviceManufacturer) sẽ được gọi là chỉ một lần?

+3

Tôi chân thành hy vọng như vậy, nếu không tôi có nhiều mã khủng khiếp để viết lại ... – skaffman

+0

bản sao có thể có của http://stackoverflow.com/questions/1618202/java-foreach-loop –

+3

@Pascal Thivent - Có, nhưng tiêu đề của tôi tốt hơn :) – morgancodes

Trả lời

18

Có, tuyệt đối.

Từ section 14.14.2 of the spec:

Nếu loại của Expression là một subtype của Iterable, sau đó cho phép tôi được kiểu của biểu thức Expression.iterator(). Việc tăng cường cho tuyên bố là tương đương với một cơ bản cho tuyên bố có dạng: (. Các thỏa thuận khác với mảng)

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

Lưu ý cách Expression chỉ được đề cập trong phần đầu của cho biểu thức vòng lặp - vì vậy nó chỉ được đánh giá một lần.

7

Vâng, hãy thử xem:

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}; 
    } 
} 

Output:

$ java ForLoop 
Test data invoked 
1 
2 
3 
4 
1

Để bổ sung cho những gì đang được nói và xác minh rằng spec là làm những gì nó nói, chúng ta hãy nhìn vào bytecode tạo ra cho lớp sau, thực hiện vòng lặp kiểu cũ và mới để lặp qua danh sách được trả về bằng một cuộc gọi phương thức, 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); 
     } 
    } 
} 

phần có liên quan của kết quả:

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 

Điều này cho thấy vòng đầu tiên (0-32) và lần thứ hai (35-67) là giống hệt.
Bytecode được tạo chính xác giống như.

+2

Oh người đàn ông ... chúng ta có ** phải xem xét bytecode không? Chúng ta không thể đi theo những gì JLS chỉ định? –

+0

LOL cảm ơn stephen, chính xác những gì tôi đã suy nghĩ. Không phải để bash OP nhưng trong bytecode ý kiến ​​của tôi không thể giúp anh ta trong trường hợp này –

Các vấn đề liên quan