2009-02-05 17 views
15

Khi tôi sử dụng một Iterator của Object tôi sử dụng một Vòng lặp while (như được viết trong mỗi cuốn sách học Java, như tư duy trong Java của Bruce Eckel) :Sự khác nhau giữa di chuyển một Iterator về phía trước với câu lệnh for và một tuyên bố trong khi

Iterator it=... 

while(it.hasNext()){ 
    //... 
} 

nhưng đôi khi tôi thấy hơn thay vì ai đó sử dụng vòng lặp for :

Iterator it=... 
for (Iterator it=...; it.hasNext();){ 
    //... 
} 

tôi không' hiểu sự lựa chọn này:

  • tôi sử dụng vòng lặp for khi tôi có một bộ sưu tập với chuỗi thứ tự (như mảng) hoặc với một quy tắc đặc biệt cho bước (tuyên bố chung như một increment đơn giản counter++).
  • Tôi sử dụng khi vòng lặp khi kết thúc vòng lặp với Tôi không có ràng buộc này nhưng chỉ có điều kiện logic để thoát.

Đó là câu hỏi về cách viết mã mà không có nguyên nhân khác hoặc tồn tại một số logic khác (ví dụ như hiệu suất) mà tôi không biết?

Cảm ơn mọi ý kiến ​​phản hồi

+0

Có một ví dụ về chuyển đổi 'Iterator' để tương thích với vòng lặp for-each 'Iterable' trong http://stackoverflow.com/questions/2598219/java-why-cant-iterate-over-an-iterator/ – Vadzim

Trả lời

32

Cú pháp chính xác cho các vòng lặp for là:

for (Iterator it = ...; it.hasNext();){ 
    //... 
} 

(Tờ khai trước trong mã của bạn là không cần thiết, cũng như dấu chấm phẩy phụ trong tiêu đề vòng lặp for.)

Cho dù bạn sử dụng cú pháp này hay vòng lặp while là một vấn đề về hương vị, cả hai đều dịch chính xác như nhau. Cú pháp tổng quát của vòng lặp for là:

for (<init stmt>; <loop cond>; <iterate stmt>) { <body>; } 

tương đương với:

<init stmt>; 
while (<loop cond>) { <body>; <iterate stmt>; } 

Edit: Trên thực tế, hai hình thức trên là không hoàn toàn tương đương, nếu (như trong câu hỏi) biến được khai báo với câu lệnh init. Trong trường hợp này, sẽ có sự khác biệt trong phạm vi của biến lặp. Với vòng lặp for, phạm vi được giới hạn trong vòng lặp, trong trường hợp của vòng lặp while, tuy nhiên, phạm vi mở rộng đến cuối khối bao quanh (không có bất ngờ lớn, vì khai báo nằm ngoài vòng lặp).

Ngoài ra, như những người khác đã chỉ ra, trong các phiên bản mới hơn của Java, có một ký hiệu viết tắt cho các vòng lặp for:

for (Iterator<Foo> it = myIterable.iterator(); it.hasNext();) { 
    Foo foo = it.next(); 
    //... 
} 

có thể được viết như sau:

for (Foo foo : myIterable) { 
    //... 
} 

Với hình thức này , tất nhiên, bạn mất tham chiếu trực tiếp tới trình vòng lặp, điều cần thiết, ví dụ, nếu bạn muốn xóa các mục khỏi bộ sưu tập trong khi lặp lại.

+0

Nếu bạn thêm vào các tham chiếu đến phạm vi giới hạn thu được từ việc sử dụng vòng lặp "for", đây sẽ là câu trả lời hoàn hảo ... –

+0

@Michael: Có bạn đi. –

9

Đây chỉ là một điều kiểu và bạn thích vòng lặp khi sử dụng thứ gì đó có chỉ mục. Nếu bạn đang sử dụng Java 5 bạn tất nhiên nên sử dụng một vòng lặp foreach qua bộ sưu tập anyway:

Collection<String> someCollection = someCollectionOfString(); 
for (String element : someCollection) { 
.... 
} 
+1

Điều duy nhất bạn bị mất bằng cách sử dụng dạng lặp này là bạn không thể gọi phương thức Iterator.remove() - vì bạn không có tham chiếu đến đối tượng Iterator. –

+1

Đúng .. nhưng bạn sẽ thấy rằng khá nhanh chết tiệt! – tddmonkey

2

Mọi người có thể sử dụng (kiểu cũ) cho vòng lặp đơn giản vì nó cảm thấy sạch hơn với họ, có lẽ họ chưa điều chỉnh cú pháp mới (cá nhân tôi nghĩ là sạch hơn nhiều).

Một lợi thế cụ thể thực tế của cấu trúc vòng lặp dài hơn là bạn có tham chiếu đến trình lặp và do đó có thể gọi các phương thức trên nó khác sau đó next(). Đặc biệt, hasNext() thường có thể hữu ích để gọi - hãy tưởng tượng nếu bạn muốn in ra một danh sách các chuỗi bằng dấu phẩy:

StringBuilder sb = new StringBuilder(); 
for (Iterator it=...; it.hasNext();){ 
    sb.append(it.next()); 
    if (it.hasNext()) 
     sb.append(", "); 
}

Nó chỉ là để phân biệt "này là người cuối cùng" trường hợp như thế này nếu bạn sử dụng chi tiết hơn cho vòng lặp.

4

Không có nhiều sự khác biệt giữa hai phương pháp, trừ phương pháp đầu tiên ghi nhớ giá trị it sau vòng lặp. Cách tiếp cận thứ hai có thể ném một lỗi, bởi vì bạn redeclare biến bên trong vòng lặp.

Có thực sự là phương pháp thứ ba cho điều này, đúng vậy. Thay vì viết e.g.

for (Iterator<SomeObject> it = foo.iterator(); it.hasNext();) { 
    SomeObject so = foo.next(); 
} 

bạn có thể thường xuyên nhất viết

for (SomeObject so: foo) {...} 

Hai bằng điều tương tự ...

9

Mục đích của tuyên bố Iterator trong vòng lặp for là giảm thiểu phạm vi biến của bạn, đây là một phương pháp hay.

Khi bạn khai báo Iterator ngoài vòng lặp, thì tham chiếu vẫn hợp lệ/còn hoạt động sau khi vòng lặp hoàn tất. 99,99% thời gian, bạn không cần phải tiếp tục sử dụng Iterator khi vòng lặp hoàn tất, do đó, một phong cách như vậy có thể dẫn đến lỗi như thế này:

//iterate over first collection 
Iterator it1 = collection1.iterator(); 
while(it1.hasNext()) { 
    //blah blah 
} 

//iterate over second collection 
Iterator it2 = collection2.iterator(); 
while(it1.hasNext()) { 
    //oops copy and paste error! it1 has no more elements at this point 
} 
Các vấn đề liên quan