2014-05-03 29 views
28

Có thể tạo một luồng từ một Iterator, trong đó chuỗi các đối tượng giống với chuỗi được tạo ra bằng cách gọi phương thức next() của trình lặp lặp lại không? Trường hợp cụ thể tôi đang nghĩ đến các mối quan tâm về việc sử dụng trình lặp được trả về bởi TreeSet.descendingIterator(), nhưng tôi có thể tưởng tượng các trường hợp khác trong đó một trình lặp, nhưng không phải là bộ sưu tập mà nó tham chiếu, có sẵn. Ví dụ, đối với một TreeSet<T> tset chúng ta có thể viết tset.stream()... và nhận được một luồng các đối tượng trong tập hợp đó, theo thứ tự sắp xếp của bộ, nhưng nếu chúng ta muốn chúng theo thứ tự khác, chẳng hạn như có sẵn thông qua việc sử dụng descendingIterator() thì sao? Tôi đang tưởng tượng một cái gì đó như tset.descendingIterator().stream()... hoặc stream(tset.descendingIterator())..., mặc dù cả hai biểu mẫu này đều không hợp lệ.Cách tạo luồng Java 8 từ trình lặp?

+0

Tôi không quá quen thuộc với Java 8, đó là lý do tôi nhận xét thay vì trả lời, nhưng bạn đang tìm kiếm [Stream] của Java (http://docs.oracle.com/javase/8/docs/ api/java/util/stream/Stream.html) giao diện? Nghe có vẻ như nó có thể phù hợp với nhu cầu của bạn (đối với một số hoạt động, ít nhất ... Không có vẻ như nó hoạt động nếu bạn cần nó hoạt động theo cách lặp lại nhiều hơn) – awksp

+0

@ user3580294 Dòng hạn không may bị quá tải , nhưng tôi đang đề cập đến giao diện java.util.stream.Stream . Tôi sẽ thêm một ví dụ. – sdenham

+0

Vì vậy, bạn muốn tạo một 'java.util.stream.Stream ' từ một 'java.util.Iterator '? – awksp

Trả lời

32

Ví dụ cụ thể của NavigableSet.descendingIterator(), tôi nghĩ cách đơn giản nhất là sử dụng NavigableSet.descendingSet() thay thế.

Nhưng với bạn có lẽ quan tâm trong trường hợp tổng quát hơn, sau đây dường như làm việc:

import java.util.Iterator; 
import java.util.Spliterator; 
import java.util.Spliterators; 
import java.util.TreeSet; 
import java.util.stream.Stream; 
import java.util.stream.StreamSupport; 

public class Streams { 
    public static void main(String... args) { 
     TreeSet<String> set = new TreeSet<>(); 
     set.add("C"); 
     set.add("A"); 
     set.add("B"); 

     Iterator<String> iterator = set.descendingIterator(); 

     int characteristics = Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED; 
     Spliterator<String> spliterator = Spliterators.spliteratorUnknownSize(iterator, characteristics); 

     boolean parallel = false; 
     Stream<String> stream = StreamSupport.stream(spliterator, parallel); 

     stream.forEach(System.out::println); // prints C, then B, then A 
    } 
} 

Tóm lại, bạn phải tạo một Spliterator từ Iterator đầu tiên bằng một trong những phương pháp tĩnh trong Spliterators . Sau đó, bạn có thể tạo một Stream bằng cách sử dụng các phương pháp tĩnh trong StreamSupport.

Tôi chưa có nhiều kinh nghiệm với việc tạo Trình tách và Luồng bằng tay, vì vậy tôi không thể thực sự nhận xét về những đặc tính nên là gì hoặc chúng sẽ có tác dụng gì. Trong ví dụ đơn giản đặc biệt này, dường như không có vấn đề gì nếu tôi xác định các đặc tính như trên, hoặc tôi đặt nó thành 0 (tức là không có đặc điểm). Ngoài ra còn có một phương pháp trong Spliterators để tạo ra một Spliterator với ước tính kích thước ban đầu - Tôi giả sử trong ví dụ cụ thể này bạn có thể sử dụng set.size(), nhưng nếu bạn muốn xử lý Iterator tùy ý tôi đoán điều này sẽ không xảy ra. Một lần nữa, tôi không hoàn toàn chắc chắn về hiệu quả của nó trên hiệu suất.

+1

Cảm ơn cả giải pháp chung và đã mang lại sự chú ý cho NavigableSet. Từ tài liệu StreamSupport, tôi thấy rằng java.util.function.Supplier cung cấp một giao diện để nạp dữ liệu vào luồng. – sdenham

+0

Xem câu trả lời được chấp nhận bên dưới, câu trả lời được chấp nhận là – Jochen

46
static <T> Stream<T> iteratorToFiniteStream(final Iterator<T> iterator) { 
    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false); 
} 

static <T> Stream<T> iteratorToInfiniteStream(final Iterator<T> iterator) { 
    return Stream.generate(iterator::next); 
} 
+0

Câu trả lời này phải là câu trả lời được chấp nhận – Jochen

+0

Tôi đồng ý và tôi biết nó hoạt động, nhưng tôi không hiểu [tại sao lambda có thể được gán cho Iterable] (http://stackoverflow.com/questions/41841310/explain-how-this-supplier-lambda-can-be-assigned-to-an-iterable) – Brad

+0

Giải pháp thứ hai sẽ dẫn đến một ngoại lệ trong nhiều trường hợp sử dụng nhất. Ví dụ: 'Iterator iterator = Arrays.asList (0, 1, 2, 3) .iterator(); Stream.generate (iterator :: next) .forEach (e -> System.out.println (e)); 'in 0, 1, 2, 3 và sau đó ném một' NoSuchElementException'. Vấn đề là 'iterator.hasNext()' không bao giờ được gọi. –

3

này không tạo ra một dòng, nhưng Iterator cũng có một phương pháp gọi là forEachRemaining:

someIterator.forEachRemaining(System.out::println); 
someIterator.forEachRemaining(s -> s.doSomething()); 
//etc. 

Đối số bạn vượt qua trong là một Consumer đó là điều tương tự để bạn vượt qua Stream::forEach.

Here are the docs cho phương pháp đó. lưu ý rằng bạn không thể tiếp tục "chuỗi" như bạn có thể với luồng. Nhưng tôi vẫn thấy điều này hữu ích một vài lần tôi đã muốn một Stream từ Iterator.

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