कैसे एक धारा प्रवाह में परिवर्तित करने के लिए?


468

मैं एक संक्षिप्त तरीके से एक कन्वर्ट करने के लिए देख रहा हूँ Iteratorएक करने के लिए Stream"दृश्य" एक धारा के रूप में इटरेटर करने के लिए या अधिक विशेष रूप से।

प्रदर्शन के कारण, मैं नई सूची में पुनरावृत्तिकर्ता की एक प्रति से बचना चाहूंगा:

Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Collection<String> copyList = new ArrayList<String>();
sourceIterator.forEachRemaining(copyList::add);
Stream<String> targetStream = copyList.stream();

टिप्पणियों में कुछ सुझावों के आधार पर, मैंने भी उपयोग करने की कोशिश की है Stream.generate:

public static void main(String[] args) throws Exception {
    Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
    Stream<String> targetStream = Stream.generate(sourceIterator::next);
    targetStream.forEach(System.out::println);
}

हालाँकि, मुझे एक मिलता है NoSuchElementException(क्योंकि वहाँ कोई मंगलाचरण नहीं है hasNext)

Exception in thread "main" java.util.NoSuchElementException
    at java.util.AbstractList$Itr.next(AbstractList.java:364)
    at Main$$Lambda$1/1175962212.get(Unknown Source)
    at java.util.stream.StreamSpliterators$InfiniteSupplyingSpliterator$OfRef.tryAdvance(StreamSpliterators.java:1351)
    at java.util.Spliterator.forEachRemaining(Spliterator.java:326)
    at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
    at Main.main(Main.java:20)

मैंने देखा है StreamSupportऔर Collectionsमुझे कुछ नहीं मिला।



3
@DmitryGinzburg euh मैं "अनंत" स्ट्रीम नहीं बनाना चाहता।
जूल

1
@DmitryGinzburg Stream.generate(iterator::next)काम करता है?
gontard

1
@DmitryGinzburg जो एक परिमित पुनरावृत्ति के लिए काम नहीं करेगा।
गधे

जवाबों:


543

एक तरीका यह है कि Iterator से एक Spliterator बनाएं और अपनी स्ट्रीम के लिए आधार के रूप में उपयोग करें:

Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Stream<String> targetStream = StreamSupport.stream(
          Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED),
          false);

एक विकल्प जो शायद अधिक पठनीय है, एक Iterable का उपयोग करना है - और एक Iterator से एक Iterable बनाना लैम्ब्डा के साथ बहुत आसान है क्योंकि Iterable एक कार्यात्मक इंटरफ़ेस है:

Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();

Iterable<String> iterable = () -> sourceIterator;
Stream<String> targetStream = StreamSupport.stream(iterable.spliterator(), false);

26
स्ट्रीम आलसी हैं: कोड केवल स्ट्रीम को Iterator से लिंक कर रहा है लेकिन वास्तविक पुनरावृत्ति टर्मिनल ऑपरेशन तक नहीं होगी। यदि आप इस बीच में पुनरावृत्ति का उपयोग करते हैं तो आपको अपेक्षित परिणाम नहीं मिलेगा। उदाहरण के लिए, आप sourceIterator.next()स्ट्रीम का उपयोग करने से पहले एक परिचय कर सकते हैं और आप प्रभाव देखेंगे (पहला आइटम स्ट्रीम द्वारा नहीं देखा जाएगा)।
assylias

9
@assylias, हाँ यह वास्तव में अच्छा है! हो सकता है कि आप भविष्य के पाठकों के लिए यह काफी जादुई रेखा बता सकें Iterable<String> iterable = () -> sourceIterator;। मुझे यह स्वीकार करना होगा कि मुझे समझने में कुछ समय लगा।

7
मुझे बताना चाहिए कि मुझे क्या मिला। Iterable<T>एक है FunctionalInterfaceजिसमें केवल एक सार विधि है iterator()। तो एक अनाम () -> sourceIteratorअभिव्यक्ति के Iterableरूप में एक उदाहरण को तुरंत एक लंबोदर अभिव्यक्ति है ।
जिन क्वोन

13
फिर से, () -> sourceIterator;छोटा रूप हैnew Iterable<>() { @Override public Iterator<String> iterator() { return sourceIterator; } }
जिन क्वाँ

7
@ जीनकॉन यह वास्तव में एक अनाम वर्ग का छोटा रूप नहीं है (कुछ सूक्ष्म अंतर हैं, जैसे कि गुंजाइश और इसे कैसे संकलित किया जाता है) लेकिन यह इस मामले में समान व्यवहार करता है।
assylias

122

संस्करण 21 के बाद से, अमरूद पुस्तकालय प्रदान करता है Streams.stream(iterator)

यह क्या करता है @ assylias का जवाब दिखाता है



ऐसे समय तक लगातार इसका उपयोग करना बेहतर है जब तक कि जेडीके एक देशी वन-लाइनर का समर्थन नहीं करता। भविष्य में इसे (इसलिए रिफ्लेक्टर) खोजना कहीं अधिक सरल होगा क्योंकि शुद्ध-जेडीके समाधान कहीं और दिखाए जाएंगे।
drekbour

यह उत्कृष्ट है लेकिन ... जावा में देशी पुनरावृत्तियां और धाराएं कैसे हैं ... लेकिन एक से दूसरे में जाने के लिए कोई अंतर्निहित, सीधा रास्ता नहीं है !? मेरी राय में काफी कमी है।
डैन लेन्स्की

92

महान सुझाव! यहाँ इस पर मेरा पुन: प्रयोज्य है:

public class StreamUtils {

    public static <T> Stream<T> asStream(Iterator<T> sourceIterator) {
        return asStream(sourceIterator, false);
    }

    public static <T> Stream<T> asStream(Iterator<T> sourceIterator, boolean parallel) {
        Iterable<T> iterable = () -> sourceIterator;
        return StreamSupport.stream(iterable.spliterator(), parallel);
    }
}

और उपयोग (सांख्यिकीय रूप से आयात करने के लिए सुनिश्चित करें)

List<String> aPrefixedStrings = asStream(sourceIterator)
                .filter(t -> t.startsWith("A"))
                .collect(toList());

43

जावा 9 में यह संभव है।

Stream.generate(() -> null)
    .takeWhile(x -> iterator.hasNext())
    .map(n -> iterator.next())
    .forEach(System.out::println);

1
सरल, कुशल और उपवर्ग का सहारा लिए बिना - यह स्वीकृत उत्तर होना चाहिए!
martyglaubitz

1
दुर्भाग्य से ये .parallel()धाराओं के साथ काम नहीं करते हैं। वे Spliteratorअनुक्रमिक उपयोग के लिए, यहां तक ​​कि ऊपर जाने की तुलना में थोड़ा धीमा दिखाई देते हैं।
थॉमस अहले

इसके अलावा, पहला तरीका फेंकता है अगर पुनरावृत्ति खाली है। दूसरी विधि अब के लिए काम करती है, लेकिन यह नक्शे में कार्यों की आवश्यकता का उल्लंघन करती है और इसे स्थिर होने में ले जाती है, इसलिए मैं उत्पादन कोड में ऐसा करने में संकोच करता हूं।
हंस-पीटर स्टॉर

वास्तव में, यह एक स्वीकृत उत्तर होना चाहिए। भले ही parallelकायरता सरल हो, आश्चर्यजनक है।
स्वेन

11

बनाएं Spliteratorसे Iteratorका उपयोग कर Spliteratorsवर्ग spliterator बनाने के लिए एक से अधिक समारोह में शामिल है, उदाहरण के लिए यहाँ उपयोग कर रहा हूँ spliteratorUnknownSizeजो इटरेटर पैरामीटर के रूप में हो रही है, तो स्ट्रीम का उपयोग कर बनाने केStreamSupport

Spliterator<Model> spliterator = Spliterators.spliteratorUnknownSize(
        iterator, Spliterator.NONNULL);
Stream<Model> stream = StreamSupport.stream(spliterator, false);

1
import com.google.common.collect.Streams;

और उपयोग करें Streams.stream(iterator):

Streams.stream(iterator)
       .map(v-> function(v))
       .collect(Collectors.toList());

-4

उपयोग Collections.list(iterator).stream()...


6
जबकि छोटा, यह बहुत कम है।
ओलिवियर ग्रेगोइरे

2
यह java ऑब्जेक्ट के लिए पूरे पुनरावृत्ति को प्रकट करेगा फिर इसे स्ट्रीम में परिवर्तित करेगा। मैं इसका सुझाव नहीं देता
iec2011007

3
यह केवल एन्यूमरेशन्स के लिए लगता है, न कि पुनरावृत्तियों के लिए।
जॉन 16384

1
सामान्य रूप से एक भयानक जवाब नहीं है, एक चुटकी में उपयोगी है, लेकिन सवाल में प्रदर्शन का उल्लेख है और जवाब प्रदर्शन नहीं है।
स्लेज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.