2014-05-04 17 views
6

Có sự khác biệt về hiệu suất giữa hai đoạn mã dưới đây không?Có sự khác biệt nào giữa hai vòng này không?

for(String project : auth.getProjects()) { 
    // Do something with 'project' 
} 

String[] projects = auth.getProjects(); 
for(String project : projects) { 
    // Do something with 'project' 
} 

Đối với tôi, tôi nghĩ rằng điều thứ hai là tốt hơn, nhưng nó là lâu hơn. Cái đầu tiên ngắn hơn, nhưng tôi không chắc nó có nhanh hơn không. Tôi không chắc chắn, nhưng với tôi nó có vẻ như mỗi khi vòng lặp đó được lặp lại, auth.getProjects được gọi. Có phải vậy không?

+0

Nó chỉ được gọi một lần, nhưng phiên bản thứ hai là quá dài dòng. Tất cả những gì bạn đang làm là trải qua một danh sách. Một dòng là đủ. – Navin

Trả lời

10

Chỉnh sửa: @StephenC là đúng, JLS là nơi tốt hơn để tìm câu trả lời cho nội dung này. Dưới đây là một số link to the enhanced for loop trong đặc tả ngôn ngữ. Trong đó bạn sẽ thấy rằng có một vài loại khác nhau của các câu lệnh mà nó tạo ra nhưng không ai trong số họ gọi phương thức này quá 1 lần.


thử nghiệm đơn giản cho thấy rằng phương pháp này chỉ được gọi một lần

public class TestA { 
    public String [] theStrings; 

    public TestA() { 
     theStrings = new String[] {"one","two", "three"}; 
     for(String string : getTheStrings()) { 
      System.out.println(string); 
     } 
    } 

    public String[] getTheStrings() { 
     System.out.println("get the strings"); 
     return theStrings; 
    } 

    public static void main(String [] args) { 
     new TestA(); 
    } 
} 

Output:

get the strings 
one 
two 
three 

Vì vậy, về cơ bản họ là những điều tương tự. Điều duy nhất có thể có lợi cho lần thứ 2 là nếu bạn muốn sử dụng mảng bên ngoài vòng lặp for.


Sửa

Bạn đã cho tôi tò mò về cách trình biên dịch java xử lý này để sử dụng các mã trên tôi dịch ngược file class và heres những gì kết quả là

public class TestA 
{ 

    public TestA() 
    { 
     String as[]; 
     int j = (as = getTheStrings()).length; 
     for(int i = 0; i < j; i++) 
     { 
      String string = as[i]; 
      System.out.println(string); 
     } 

    } 

    public String[] getTheStrings() 
    { 
     System.out.println("get the strings"); 
     return theStrings; 
    } 

    public static void main(String args[]) 
    { 
     new TestA(); 
    } 

    public String theStrings[] = { 
     "one", "two", "three" 
    }; 
} 

Như bạn có thể xem trình biên dịch chỉ đơn giản là cấu trúc lại vòng lặp của bạn thành một vòng lặp tiêu chuẩn! Nó cũng chứng minh thêm rằng trong thực tế, chúng là chính xác như nhau sau khi trình biên dịch được thông qua với nó.

+0

Cảm ơn bạn. Bây giờ tôi có một ý tưởng rõ ràng những gì thực sự diễn ra đằng sau hậu trường. – hamid

+3

* "Thử nghiệm đơn giản cho thấy phương pháp này chỉ được gọi một lần" * - Các phép thử đơn giản có thể gây hiểu nhầm ... 'cos bạn không biết bạn nên kiểm tra cái gì. Cách tiếp cận tốt hơn là đọc JLS. –

+0

+1 cho lời giải thích hay của bạn –

-1

Cách thứ hai hiệu quả hơn, không tạo ra biến nhiều lần. Vì vậy, có, auth.getProjects đang được gọi mỗi lần.

+0

Không đúng. Biến cục bộ để giữ 'auth.getProjects()' được tạo và được chỉ định một lần. Xem trả lời của tôi. –

+0

Xin lỗi về điều đó, tôi đã viết rằng vào ban đêm xD – loafy

3

Có một vài thao tác khác trong ví dụ thứ hai. Thay vì tham chiếu mảng trực tiếp bằng cách sử dụng phương thức, bạn khai báo một biến tham chiếu mới, lưu nó vào biến mới đó, sau đó tham chiếu biến mới.

Bạn có thể kiểm tra bytecode với ASM Bytecode Outline.

NHƯNG, đây là tối ưu hóa vi mô. Nếu bạn cần biến tham chiếu mới, hãy tạo biến tham chiếu. Nếu bạn không cần, hãy lưu công việc và không tạo một tác phẩm mới.

+1

Ý của bạn là "ví dụ thứ hai" thay vì "ví dụ đầu tiên"? Ví dụ thứ hai là ví dụ khai báo biến tham chiếu mới. Mặc dù, nếu biến tham chiếu không được sử dụng ở nơi khác trong hàm, hầu hết các trình biên dịch có thể sẽ sử dụng một thanh ghi cho nó trong cả hai trường hợp. –

+1

@WarrenDew Có, tôi đã chỉnh sửa câu trả lời của tôi, cảm ơn bạn đã chỉ ra rằng –

3

Giả sử rằng theo in bạn có nghĩa là :, không có sự khác biệt về hiệu suất; cả hai đều làm điều tương tự. Ngay cả trong ví dụ đầu tiên, auth.getProjects() chỉ được thực thi một lần; nó không thể được thực hiện nhiều lần, vì nếu nó được, các iteration for sẽ phải bắt đầu lại mỗi lần, mà không phải là cách nó hoạt động.

Tôi khuyên bạn nên sử dụng phiên bản bạn thấy rõ ràng hơn.

-1

Cả hai đều giống như được tìm thấy ở trên.

Nhưng làm một việc sử dụng lần thứ nhất và sau vòng lặp for, hãy tham khảo biến dự án là dự án = null; Khác, nó sẽ vẫn còn sống cho cuộc sống phương pháp hoàn chỉnh và sẽ tiêu thụ bộ nhớ không cần thiết.

+0

Không chính xác. Phương thức getProjects không được gọi là "trong vòng lặp". Nó được gọi là một lần, ở đầu vòng lặp. –

+0

Thay đổi nó dựa trên câu trả lời đúng. – 53by97

2

Không có sự khác biệt.

Theo JLS 14.14.2, một cải tiến for vòng (đối với một kiểu mảng) là tương đương với một for vòng lặp thường xuyên với các mẫu sau:

T[] #a = Expression; 
L1: L2: ... Lm: 
for (int #i = 0; #i < #a.length; #i++) { 
    {VariableModifier} TargetType Identifier = #a[#i]; 
    Statement 
} 

Nếu chúng ta thay thế cho ví dụ đầu tiên của bạn:

for(String project : auth.getProjects()) { 
    // Do something with 'project' 
} 

chúng tôi nhận được:

String[] $a = auth.getProjects(); 
for (int $i = 0; $i < $a.length; $i++) { 
    String project = $a[$i]; 
    // Do something with 'project' 
} 

Ví dụ thứ hai của bạn:

String[] projects = auth.getProjects(); 
for(String project : projects) { 
    // Do something with 'project' 
} 

chúng tôi nhận được:

String[] projects = auth.getProjects(); 
String[] $a = projects; 
for (int $i = 0; $i < $a.length; $i++) { 
    String project = $a[$i]; 
    // Do something with 'project' 
} 

Hai phiên bản của mã rõ ràng là tương đương, và giả định rằng javac hoặc JIT có khả năng tối ưu hóa đi các biến địa phương thừa $a , hai phiên bản sẽ thực hiện tương tự.

Lưu ý rằng biến cục bộ $a chỉ được tạo một lần khi bắt đầu vòng lặp trong cả hai trường hợp.

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