2008-10-10 34 views
12

Cá nhân, tôi thấy phạm vi chức năng được cung cấp bởi java.util.Iterator là khá thảm hại. Ở mức tối thiểu, tôi muốn có các phương pháp như:Bộ sưu tập cải tiến Iterator

  • peek() trả về phần tử tiếp theo mà không cần di chuyển iterator về phía trước
  • trước() trả về phần tử trước

Mặc dù có nhiều khả năng khác như first() và last().

Có ai biết nếu trình vòng lặp bên thứ ba như vậy tồn tại không? Nó có lẽ sẽ cần phải được thực hiện như là một trang trí của java.util.Iterator để nó có thể làm việc với các bộ sưu tập java hiện có. Lý tưởng nhất, nó nên là "generics nhận thức".

Cảm ơn trước, Don

Trả lời

8
+1

Cảm ơn, nhưng AFAIK bộ sưu tập commons Apache * vẫn * chưa được mở rộng –

+0

cả hai liên kết này đều đã chết – Quince

+0

sửa liên kết, cảm ơn. Apache giờ đây cũng đã nhận biết về generics và Bộ sưu tập của Google có sẵn như một phần của ổi. – ykaganovich

9

Bạn có thể nhận previous() dễ dàng bằng cách chỉ sử dụng một java.util.ListIterator.

Peek vào thời điểm đó có thể dễ dàng thực hiện bằng cách làm một

public <T> T peek(ListIterator<T> iter) throws NoSuchElementException { 
    T obj = iter.next(); 
    iter.previous(); 
    return obj; 
} 

Đáng tiếc là nó sẽ được dễ dàng hơn để có nó như là một phương pháp hữu ích vì mỗi lớp thu thực hiện lặp riêng của họ. Để làm một wrapper để có được một phương pháp peek trên mỗi bộ sưu tập trên một số giao diện như MyListIterator sẽ được khá nhiều công việc.

8

Tôi nghĩ lý do không được thực hiện là vì chúng không tầm thường đối với một số bộ sưu tập và sẽ có tác động hiệu suất lớn. Tôi nghĩ rằng nó sẽ được khá đơn giản cho bạn để làm cho công việc này cho các bộ sưu tập bạn quan tâm. Tôi cũng không thích các trình lặp Java không có cách nào nhận được giá trị hiện tại mà không di chuyển nó (và do đó bạn không thể dễ dàng viết mã mà các nhánh dựa trên giá trị, chỉ cần chuyển qua trình vòng lặp - bạn phải vượt qua giá trị hiện tại của bạn).

0

Tôi chưa bao giờ gặp sự cố khi tôi cần một peek(); Iterator đã làm việc tốt cho tôi. Tôi tò mò về cách bạn đang sử dụng trình vòng lặp mà bạn cảm thấy bạn cần thêm chức năng này.

+0

Tôi nghĩ rằng trường hợp phổ biến nhất là một số loại công văn. Bạn muốn đọc phần tử đầu tiên để xem ai sẽ xử lý nó và gửi đi - nếu người nhận cần toàn bộ chuỗi thì tốt đẹp là chỉ cần vượt qua điều đó và không phải vượt qua đối tượng đã loại bỏ. –

+0

Tôi có thể thấy điều đó. Nó chỉ có mùi cho nó của một cái gì đó mà có thể được thực hiện dễ dàng hơn một số cách khác như một khách truy cập hoặc một cái gì đó. –

3

Một điều tôi sẽ xem xét là việc thực hiện Seq trong clojure

http://clojure.org/sequences

Việc thực hiện của các cơ sở lớp học nằm trong Java và nguồn đầy đủ có sẵn. Seqs là các trang trí trên các trình lặp Java (lấy và thực hiện các giao diện lặp của Java) - nhưng chúng cũng cung cấp giao diện riêng của chúng, có thể có nhiều hơn những gì bạn muốn - hoặc ít nhất là một điểm khởi đầu.

0

Có vẻ như bạn có thể được tốt hơn bằng cách sử dụng một Stack.

4

Có lý do chính đáng để các nhà khai thác chung không triển khai các tính năng này: chúng không tồn tại cho tất cả các vùng chứa. Ví dụ điển hình là một vùng chứa biểu diễn một số dữ liệu đầu vào bên ngoài, như một tệp được xem như một luồng.Mỗi khi bạn đọc một giá trị, bạn tiêu thụ và di chuyển con trỏ tiến lên, nếu bạn muốn hay không. Nếu bạn áp đặt các ràng buộc này trên các trình vòng lặp chung, thì bạn sẽ mất đi tính tổng quát của các trình vòng lặp.

Nếu bạn muốn có phương pháp previous, như được đề xuất, hãy sử dụng ListIterator<>, sau đó được giới hạn trong vùng chứa hoạt động dưới dạng danh sách.

+0

Đối số tệp không thực sự thuyết phục, không có lý do gì khiến chúng tôi không thể nhận được ký tự hiện tại (hoặc bất kỳ ký tự nào chúng tôi đang đọc) mà không cần chuyển con trỏ vào tệp. Tuy nhiên, tôi đồng ý rằng tính năng 'trước' không thể được cung cấp bởi mỗi trình lặp (đặc biệt là trình tạo vòng lặp" máy phát điện ", tạo ra một giá trị mới ở mỗi bước). –

+0

@Luc: điều này là do bạn thấy tệp là truy cập ngẫu nhiên. Và họ thực sự không cần phải như vậy. Nếu bạn thích, hãy xem xét một luồng như các ổ cắm mạng. Bạn đọc những gì bạn nhận được, và nếu bạn muốn đọc trước, bạn cần một cơ chế bộ nhớ đệm toàn bộ. Vì vậy, nếu bạn muốn trình lặp của bạn được sử dụng trong mọi tình huống, bạn * thực sự * cần giao diện Java đang cung cấp. Sau đó, bạn có thể sử dụng bộ điều hợp, hoặc nhiều bộ lặp chuyên dụng hơn. Nó vẫn là giao diện Java cung cấp là một giao diện hợp lý nhất cho các trình vòng lặp chung. – PierreBdR

+0

Đây không phải là vấn đề truy cập ngẫu nhiên: ngay cả trên luồng chỉ chuyển tiếp, tôi không thấy lý do tại sao truy cập giá trị vừa đọc và đọc tiếp theo nên được coi là một thao tác đơn lẻ. Nhưng tôi đoán điều này là khá chủ quan, và rằng chúng tôi sẽ phải đồng ý không đồng ý :). Tuy nhiên, tôi muốn thêm rằng tôi thấy nó hơi lạ khi có phương thức 'remove' trên một giao diện được cho là rất chung chung, khi loại bỏ là một thao tác chỉ có thể trên một tập hợp các đối tượng có thể lặp lại khá hạn chế . –

1

Như ykaganovich đề xuất, bạn có thể muốn xem nội dung google-collections. Chắc chắn có một số hỗ trợ cho một số điều bạn muốn, như peeking. Ngoài ra, như một số người khác đã đề cập, thực hiện tất cả những điều này cho tất cả các bộ sưu tập có thể nguy hiểm từ một khả năng hoặc quan điểm hiệu suất.

0

Bộ sưu tập Java được viết để cung cấp một bộ chức năng hữu ích tối thiểu. Đây là một cách tiếp cận rất tốt cho mã mà được thực hiện bởi bất kỳ ai đang triển khai Java. Làm nổi bật giao diện có chức năng có thể hữu ích có thể dẫn đến tăng đáng kể khối lượng mã với các cải tiến chỉ được một vài người nhận thấy. Nếu peek() và trước đó() là một phần của trình vòng lặp chuẩn có nghĩa là mọi người viết một loại Bộ sưu tập mới phải thực hiện nó, cho dù đó là hợp lý hay không.

Bộ lặp cũng được thiết kế để hoạt động trên những thứ vật lý không thể quay lại, làm cho peek() và trước() đều không thể.

1
public class Iterazor<T> { 
    private Iterator<T> it; 
    public T top; 
    public Iterazor(Collection<T> co) { 
    this.it = co.iterator(); 
    top = it.hasNext()? it.next(): null; 
    } 
    public void advance() { 
    top = it.hasNext()? it.next(): null; 
    } 
} 

// usage 

for(Iterazor<MyObject> iz = new Iterazor<MyObject>(MyCollection); 
    iz.top!=null; iz.advance()) 
    iz.top.doStuff(); 
} 
1

Tôi thấy một người nào đó được liên kết với Google Bộ sưu tập, nhưng không ai đề cập rằng phương pháp bạn đang tìm kiếm được gọi là Iterators.peekingIterator().

Tuy nhiên, sẽ tốt nhất nếu bạn chỉ có thể sử dụng Trình kiểm tra danh sách.