2012-09-29 28 views
8

Cách tốt nhất để lặp qua một mảng khi bạn cần chỉ mục là gì?Thực hành tốt nhất cho Java vòng lặp

Lựa chọn 1:

int len = array.length; 
for (int i = 0; i < len; ++i) { 
    array[i] = foo(i); 
} 

Phương án 2:

for (int i = 0; i < array.length; i++) { 
    array[i] = foo(i); 
} 

Hoặc, nó không quan trọng? Hoặc có cách nào tốt hơn để làm điều đó? Chỉ để chỉ ra sự khác biệt: Trong một trường hợp, độ dài của mảng được đánh giá là một phần của thử nghiệm trong vòng lặp, mặc dù trình biên dịch bình thường nên tối ưu hóa điều đó.


Thứ hai, là ++i khác biệt nào ở đây từ i++? Tôi chắc chắn thích ++i nếu nó là C++ nhưng không chắc chắn cho Java.

+3

Những không nên có bất kỳ khác nhau. –

Trả lời

6

i++ vs ++i không quan trọng trong trường hợp cụ thể này. Trong khi các bậc thầy C sẽ cho bạn biết để lưu trữ array.length trong một biến, các trình biên dịch tối ưu hóa hiện đại làm cho điều đó không cần thiết trong trường hợp này miễn là độ dài không thay đổi trong vòng lặp. Nếu bạn thực sự quan tâm bạn có thể điểm chuẩn cả hai, nhưng kể từ khi .length không thực sự cần phải đi qua toàn bộ mảng mỗi khi bạn sẽ được OK.

+0

Câu trả lời hay! Trên thực tế nó cũng được khuyến khích để luôn luôn sử dụng tùy chọn 1, phải không? –

+0

Tùy chọn 1 cho câu hỏi nào? Để 'i + +' so với '+ + i'? Tôi thích 'i ++' vì lý do dễ đọc hơn, nhưng tôi có thể thấy lý do tại sao' + + i' có thể là một giá trị mặc định tốt hơn, do đó giá trị mới của 'i' được sử dụng trong trường hợp bạn thay đổi mã và không nhận thấy postincrement. '++ i' cũng nhanh hơn cho các trình biên dịch ngu ngốc mà không nhận ra rằng người dùng không quan tâm giá trị của biểu thức. – Dan

+0

Không, ý tôi là tùy chọn 1 cho '.length'. Đối với '++ i' so với' i ++ ', tôi nghĩ đó chỉ là vấn đề kiểu mã. –

6

Nói chung hai phương pháp đó là tương đương. Bạn nên lưu ý rằng trong

for (int i = 0 ; i < foo() ; i++) { 
    ... 
} 

các foo() được gọi là một lần trước mỗi lần lặp (như trái ngược với chỉ một lần trước khi phiên đầu tiên), vì vậy bạn có thể muốn thực hiện việc này vào tài khoản cho các tình huống phức tạp hơn bởi lẽ làm một cái gì đó như

int n = foo(); 
for (int i = 0 ; i < n ; i++) { 
    ... 
} 

mà là tương tự như của bạn Lựa chọn 1. Vì vậy, tôi sẽ nói Tùy chọn 1 chắc chắn là an toàn hơn trong hai, nhưng hầu hết thời gian nó không nên tạo sự khác biệt đáng kể mà bạn sử dụng.


Đối với câu hỏi thứ hai của bạn: ++i gia số đầu tiên biến của bạn và sau đó lấy giá trị của nó, i++ đầu tiên lấy giá trị và sau đó tăng. Chỉ cần cố gắng hai mảnh các mã:

int i = 0; 
System.out.println(++i); 
------------------------ 
int i = 0; 
System.out.println(i++); 

Các bản in đầu tiên 1 nhưng các bản in thứ hai 0. Tất nhiên khi ++ii++ là một mình nó làm cho không có sự khác biệt.

+0

Tôi không thấy 'i

+0

@BheshGurung Hàm 'foo' đó chứng tỏ cách mà các điều kiện vòng lặp được đánh giá lặp đi lặp lại, như tôi đã đề cập. Khi bạn có một cái gì đó như 'array.length' trên rhs, nó sẽ không tạo ra sự khác biệt nào. Nhưng khi bạn có một cái gì đó như 'foo', bạn nên thận trọng ở một mức độ nào đó. – arshajii

+0

@arshajii Tôi đã lo lắng rằng foo() trong trường hợp kích thước() truy cập sẽ làm chậm những điều và tôi chạy một số thử nghiệm (xem câu trả lời cuối cùng). Rõ ràng là như nhau. Liệu trình biên dịch chỉ cần chuyển đổi kích thước() để truy cập var đơn giản tại thời gian biên dịch? – Ced

0

cho dù sử dụng "array.length" trong vòng lặp for: Nói chung trình biên dịch sẽ làm một số tối ưu hóa, kết quả là nó tương đương với sử dụng một biến trong vòng lặp for

cho "i ++" và " ++ i " Trong C++, ++ tôi được ưu tiên và hiệu quả hơn, nhưng trong Java, chúng tương đương trong trường hợp này.

0

Ngoài phản hồi arshaji tôi muốn biết nếu có lợi ích hiệu suất khi sử dụng size() trong vòng lặp và lưu trữ trước.Tôi tin rằng kết quả cho thấy trình biên dịch tối ưu hóa mọi thứ và truy cập vào chiều dài của một danh sách giống như truy cập một biến (tôi lo rằng thực tế nó phải trải qua một hàm sẽ làm chậm mọi thứ).

Đây là thời gian cần thiết cho những người hai cho phương pháp khác nhau của vòng lặp:

for(long i = 0 ; i < mylist.size(); i++){} 
VS 
for(long i = 0 ; i < 10_000_000; i++){} 

Dưới đây là kết quả cho một danh sách mười triệu elems:

fixed length: 
,162,157,151,157,156,159,157,149,150,170,158,153,152,158,151,151,156,156,151,153 
getSize: 
,164,156,159,154,151,160,162,152,154,152,151,149,168,156,152,150,157,150,156,157 



import java.util.ArrayList; 
import java.util.List; 

public class Main { 

    final static int LENGTH_SAMPLE = 20; 
    final static long LENGTH = 10_000_000; 

    public static void main(String[] args) { 

     List<Long> mylist = new ArrayList<>(); 
     for(long i = 0 ; i < LENGTH; i++){ 
      mylist.add(i); 
     } 
     System.out.println("fixed length:"); 
     for(int i = 0 ; i < LENGTH_SAMPLE; i++){ 
      System.out.printf("," + fixedSize(mylist)); 
     } 
     System.out.println(""); 
     System.out.println("getSize:"); 
     for(int i = 0 ; i < LENGTH_SAMPLE; i++){ 
      System.out.printf("," + fctSize(mylist)); 
     } 
    } 

    private static long fixedSize(List list){ 
     long start = System.currentTimeMillis(); 

     for(long i = 0 ; i < LENGTH; i++){ 
      System.currentTimeMillis(); 
     } 
     return System.currentTimeMillis() - start; 
    } 

    private static long fctSize(List list){ 
     long start = System.currentTimeMillis(); 

     for(long i = 0 ; i < list.size(); i++){ 
      System.currentTimeMillis(); 
     } 
     return System.currentTimeMillis() - start; 
    } 
} 
Các vấn đề liên quan