Tại sao Iterator và ListIterator của Java chỉ điểm giữa các phần tử?


9

Các Javadoc cho ListIterator nói:

A ListIteratorkhông có phần tử hiện tại; vị trí con trỏ của nó luôn nằm giữa phần tử sẽ được trả về bởi một cuộc gọi đến previous()và phần tử sẽ được trả về bởi một cuộc gọi đến next().

Tại sao Java được ListIteratortriển khai để chỉ giữa các phần tử chứ không phải tại một phần tử hiện tại? Dường như điều này làm cho mã khách hàng ít có thể đọc được khi nó phải liên tục gọi getNext(), getPrevious()nên tôi giả sử có phải là một lý do chính đáng cho sự lựa chọn.

Là một mặt lưu ý, tôi chỉ viết một chút thư viện gọi peekable-ArrayList mà kéo dài ArrayList, IteratorListIteratorcung cấp một peekAtNext()peekAtPrevious()phương pháp thực hiện như sau:

  @Override public synchronized T peekAtNext() {
     T t = next();
     previous();
     return t;
  }

2
Có một trình vòng lặp có thể nhìn thấy trong thư viện Guava code.google.com/p/guava-lologists
kevin cline

Cảm ơn Kevin! Tôi đã đăng một câu hỏi tiếp theo cho vấn đề này trên SO: Có thể sử dụng ForwardingListIterator của Guava với PeekingIterator không?
glenviewjeff

Câu trả lời:


12

Theo như tôi có thể nói, lý do có thể được tìm thấy trong phần javadoc mà bạn không trích dẫn (nhấn mạnh bên dưới của tôi):

Trình lặp cho các danh sách cho phép lập trình viên duyệt qua danh sách theo một trong hai hướng, sửa đổi danh sách trong khi lặp ...

Bạn thấy, mục đích dự định là cho phép sử dụng trong khi danh sách đang được sửa đổi. Sửa đổi có thể rõ ràng bao gồm loại bỏ các yếu tố.

Bây giờ hãy nghĩ về những gì sẽ xảy ra nếu chúng ta loại bỏ một phần tử sẽ current()dành cho iterator - giả sử rằng iterator sẽ có một khái niệm về phần tử hiện tại? Trong bối cảnh này, cách để thực hiện nó mà không có khái niệm về yếu tố hiện tại có ý nghĩa khá tốt đối với tôi - bởi vì theo cách đó, iterator không phải lo lắng về việc loại bỏ các yếu tố.


Điều quan trọng cần lưu ý là javadoc không yêu cầu triển khai giao diện phải an toàn cho luồng.

  • Do đó, người ta không nên mong đợi xử lý chính xác các sửa đổi được thực hiện từ các luồng khác nhau - vì điều đó, việc triển khai sẽ phải cung cấp các phương tiện bổ sung để đồng bộ hóa quyền truy cập, đảm bảo khả năng hiển thị, v.v. như được chỉ định bởi Mô hình bộ nhớ Java trên mỗi JSR 133 .

Những gì ListIterator có khả năng, là xử lý các sửa đổi được thực hiện từ cùng một luồng khi lặp. Không phải tất cả các trình vòng lặp đều như vậy, javadocs đồng thời đặc biệt cảnh báo về điều này:

... Lưu ý rằng ngoại lệ này không phải lúc nào cũng chỉ ra rằng một đối tượng đã được sửa đổi đồng thời bởi một luồng khác. Nếu một luồng duy nhất đưa ra một chuỗi các yêu cầu phương thức vi phạm hợp đồng của một đối tượng, thì đối tượng đó có thể ném ngoại lệ này. Ví dụ: nếu một luồng sửa đổi trực tiếp một bộ sưu tập trong khi nó đang lặp qua bộ sưu tập với một trình vòng lặp không nhanh, thì trình vòng lặp sẽ ném ngoại lệ này ...


1
Điều đó cũng có nghĩa là bạn không cần riêng biệt insertBeforeinsertAftermặc dù đó không phải là vấn đề lớn như a remove.
Karl Bielefeldt

1
Vì vậy, vấn đề mà người ta có thể đồng thời loại bỏ và truy cập vào phần tử hiện tại? Đây sẽ không phải là vấn đề tương đương như gọi đồng thời next()? remove()sẽ synchronizednhư sẽ getCurrent(). Tui bỏ lỡ điều gì vậy?
glenviewjeff

@glenviewjeff đó là một quan sát rất tốt. Tôi cũng tự hỏi làm thế nào CME có thể được xử lý ở đó - ý định rất rõ ràng để cho phép sửa đổi làm tăng mối lo ngại như thế. Đoán tôi cần phải đào sâu hơn. Tôi chắc chắn 99,99% nó không nhằm mục đích an toàn cho luồng, có lẽ nó chỉ có thể xử lý các mod đồng thời được thực hiện từ cùng một luồng (không phải tất cả các trình lặp đều có khả năng đó, bạn biết đấy)
gnat

Nếu bạn quan tâm, xem chỉnh sửa của tôi. Tôi đã thực hiện và đóng gói một phần mở rộng ArrayListđể thực hiện điều này.
glenviewjeff

@glenviewjeff thú vị. Trong triển khai của bạn, tiếp theo () và trước đó () cũng đồng bộ hóa? Tôi hỏi bởi vì nếu không, thì luồng khác có thể "khoan" một số bước di chuyển bất ngờ ngay vào giữa () hiện tại của bạn, khiến nó hoạt động không hoàn toàn giống như khách hàng mong đợi ... Các phương thức như add () cũng có thể cần đồng bộ hóa
gnat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.