2016-01-16 6 views
7

यह सर्वविदित है जावाडोक का कहना है कि Stream के बारे में इंटरफ़ेस:बंद मैप किए गए स्ट्रीम - क्या विचार है?

स्ट्रीम एक BaseStream.close() विधि है और AutoCloseable, लगा देंगी, लेकिन लगभग सभी धारा उदाहरणों वास्तव में उपयोग के बाद बंद कर दिया की जरूरत नहीं है। आम तौर पर, केवल उन स्रोतों को स्ट्रीम करता है जिनके स्रोत आईओ चैनल (जैसे फ़ाइलें.लाइन (पथ, वर्णसेट) द्वारा लौटाए गए हैं) को बंद करने की आवश्यकता होगी। अधिकांश धाराएं संग्रह, सरणी, या फ़ंक्शंस उत्पन्न करती हैं, जिनके लिए कोई विशेष संसाधन प्रबंधन की आवश्यकता नहीं होती है। (एक धारा समापन की आवश्यकता होती है, तो यह एक कोशिश के साथ-संसाधनों बयान में एक संसाधन के रूप में घोषित किया जा सकता है।)

ठीक है, लेकिन वहाँ एक ही समय में इस इंटरफ़ेस में flatMapToInt तरह तरीके हैं:

IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper); 

जिसके लिए जावाडोक विनिर्देश का कहना है: के बाद इसकी सामग्री इस धारा में रखा गया है

प्रत्येक मैप की धारा बंद कर दिया है। यदि IntStream, अपने स्रोत में आईओ चैनल पाने के लिए नहीं बनाया गया है कारण है कि यह इस पद्धति के अंदर बंद कर दिया है:

तो, मैं विचार नहीं मिला था?

उदाहरण के लिए, ReferencePipeline कार्यान्वयन यह करता है इस तरह से:

try (IntStream result = mapper.apply(u)) {  
    if (result != null) 
     result.sequential().forEach(downstreamAsInt); 
} 

अधिक सामान्य प्रश्न हो सकता है: हम IntStream (या उसके वंश) या नहीं की तरह धाराओं बंद करने के बारे ध्यान देना चाहिए? यदि नहीं, तो flatMapTo* देखभाल क्यों करती है?

EDIT @ टुनकी ने बहुत रोचक email link प्रदान किया है। लेकिन यह सब flatMap है, जहां मैं सहमत हूं कि हमें सामान्य मामले में धारा बंद करनी चाहिए। लेकिन मेरा सवाल विशेष मामलों के बारे में है: flatMapToInt, flatMapToLong और इसी तरह, जहां मुझे बंद धाराओं की कोई आवश्यकता नहीं दिखाई देती है।

संपादित -2 @BrianGoetz यहाँ की अपील की है, क्योंकि यह उसकी उद्धृत ईमेल है, इसलिए वह इस विषय में है :)

+6

'flatMapToInt' को' flatMap' से अलग 'का इलाज करने का कोई मतलब नहीं है। एक 'इंटस्ट्रीम' भी संसाधनों को पकड़ सकता है; सिर्फ इसलिए कि पूंछ के अंत से क्या आता है 'int' है, इसका मतलब यह नहीं है कि स्रोत गैर-स्मृति संसाधन से शुरू नहीं हुआ है। उदाहरण के लिए, मान करता 'flatMapToInt' प्रत्येक तत्व का' Files.lines()। mapToInt (स्ट्रिंग :: लंबाई) को flatmapped है '? –

उत्तर

14

संसाधन प्रबंधन के बारे में सामान्य नियम है कि whoever is responsible for closing a resource is the one that opened it है। flatMap ऑपरेशन स्ट्रीम एपीआई में एकमात्र ऑपरेशन है जो Stream खोलता है, इसलिए यह एकमात्र ऑपरेशन है जो इसे बंद कर देगा।

this mail से हवाला देते हुए, ब्रायन गोएज़ ने कहा:

संक्षेप में, flatMap() केवल आपरेशन कि आंतरिक रूप से अपने किया के बाद धारा बंद कर देता है है, और अच्छे कारण के लिए - यह केवल मामला है जहां स्ट्रीम ऑपरेशन द्वारा प्रभावी ढंग से खोला जाता है, और इसलिए ऑपरेशन द्वारा भी बंद किया जाना चाहिए। किसी भी अन्य धारा को कॉलर द्वारा खोला जाता है, और इसलिए कॉलर द्वारा बंद किया जाना चाहिए।

उदाहरण दिए गए इस प्रकार है। पर विचार करें

try (Stream<Path> paths = Files.walk(dir)) { 
    Stream<String> stream = paths.flatMap(p -> { 
     try { 
      return Files.lines(p); 
     } catch (IOException e) { 
      throw new UncheckedIOException(e); 
     } 
    }); 
} 

विधि संदर्भ Files::lines फ़ाइल की लाइनों की एक Stream<String> देता है। जब फ्लैट मैपिंग ऑपरेशन खत्म हो जाता है, तो यह अपेक्षा की जाती है कि फ़ाइल को पढ़ने के लिए उपयोग किया गया खोला संसाधन बंद है। सवाल यह है कि क्या बंद है? खैर, flatMap द्वारा खुद को बंद कर दिया क्योंकि यह वह ऑपरेशन है जिसने स्ट्रीम को पहली जगह खोला था।

Files.lines पूर्व-पंजीकृत बंद हैंडलर के साथ एक स्ट्रीम देता है जो अंतर्निहित BufferedReader को बंद करता है। जब फ्लैटमैप ऑपरेशन किया जाता है, तो यह करीबी हैंडलर लगाया जाता है और संसाधनों को सही ढंग से जारी किया जाता है।


कारण यह विचार flatMapTo* संचालन बैकपोर्टेड है एक ही है: उपरोक्त नियम यह है कि एक प्रक्रिया द्वारा आवंटित हर संसाधन है कि इस प्रक्रिया द्वारा बंद कर दिया जाना चाहिए का पालन कर।

बस यह दिखाने के लिए कि आप IntStream का निर्माण कर सकते हैं, जिसके पास अंतर्निहित संसाधन होगा, निम्नलिखित स्ट्रीम पाइपलाइन पर विचार करें जहां प्रत्येक पथ अपनी लाइनों पर फ्लैटमैप नहीं किया गया है बल्कि प्रत्येक पंक्ति में वर्ण की संख्या है।

try (Stream<Path> paths = Files.walk(dir)) { 
    IntStream stream = paths.flatMapToInt(p -> { 
     try { 
      return Files.lines(p).mapToInt(String::length); 
     } catch (IOException e) { 
      throw new UncheckedIOException(e); 
     } 
    }); 
} 
+0

* किसी भी अन्य धाराओं कॉल करने वाले को कॉल करने वाले को खोले जाने के लिए ग्रहण कर रहे हैं, और इसलिए बंद कर दिया जाना चाहिए * - इसका मतलब है कि हम 'कोशिश-साथ-resourse के साथ सभी धाराओं के साथ काम करना चाहिए (जैसे कि कुछ' list.stream() ') 'निर्माण ?? – Andremoniy

+1

@Andremoniy यह स्ट्रीम के बहुमत के लिए एक नो-ऑप होगा। केवल एक ही संबंधित अंतर्निहित संसाधनों से निपटने वाला है जिसे बंद किया जाना चाहिए। – Tunaki

+0

ठीक है, 'flatMap' मैं मानता हूँ, लेकिन' के साथ विचार के लिए इंट/LongStream's – Andremoniy

संबंधित मुद्दे