जावा में, लूप पर धाराओं के क्या फायदे हैं? [बन्द है]


133

मुझे एक साक्षात्कार में यह पूछा गया था और मुझे यकीन नहीं है कि मैंने सबसे अच्छा जवाब दिया जो मैं कर सकता था। मैंने उल्लेख किया है कि आप एक समानांतर खोज कर सकते हैं और उस शून्य मान को कुछ ऐसे साधनों द्वारा संभाला जाता है जिन्हें मैं याद नहीं रख सकता। अब मुझे एहसास हुआ कि मैं ऑप्शनल के बारे में सोच रहा था। मुझे यहां क्या समझ नहीं आ रहा है? वे दावा करते हैं कि यह बेहतर या अधिक संक्षिप्त कोड है, लेकिन मुझे यकीन नहीं है कि मैं सहमत हूं।


यह देखते हुए कि यह कैसे उत्तर दिया गया था, ऐसा लगता है कि यह सब के बाद एक व्यापक प्रश्न नहीं था।


यदि वे साक्षात्कार में यह सवाल पूछ रहे हैं, और स्पष्ट रूप से वे हैं, तो इसका क्या उद्देश्य हो सकता है कि वह इसका जवाब देने के अलावा अन्य कठिन कामों को पूरा कर सकें? मेरा मतलब है, तुम क्या देख रहे हो? मैं प्रश्न को तोड़ सकता था और सभी उप-प्रश्नों के उत्तर दे सकता था, लेकिन फिर सभी उपवर्गों के लिंक के साथ एक मूल प्रश्न बना सकता हूं ... हालांकि बहुत मूर्खतापूर्ण लगता है। जब हम इस पर होते हैं, तो कृपया मुझे एक कम व्यापक प्रश्न का एक उदाहरण दें। मुझे इस प्रश्न का केवल एक हिस्सा पूछने का कोई तरीका नहीं पता है और फिर भी इसका सार्थक उत्तर मिलता है। मैं बिल्कुल अलग तरीके से एक ही सवाल पूछ सकता था। उदाहरण के लिए, मैं पूछ सकता हूं "धाराएं किस उद्देश्य से काम करती हैं?" या "मैं लूप के बजाय एक स्ट्रीम का उपयोग कब करूंगा?" या "लूप के बजाय धाराओं के साथ परेशान क्यों?" ये सभी बिल्कुल एक ही सवाल हैं।

... या इसे बहुत व्यापक माना जाता है क्योंकि किसी ने वास्तव में लंबे समय तक बहु-बिंदु उत्तर दिया था? सच में किसी को भी पता है कि लगभग किसी भी सवाल के साथ कर सकता है। यदि आप जेवीएम के लेखकों में से एक हैं, उदाहरण के लिए, आप शायद उन सभी दिनों के लिए लूप के बारे में बात कर सकते हैं जब हम में से अधिकांश नहीं कर सकते थे।

"कृपया पर्याप्त उत्तर की पहचान करने के लिए प्रश्न को किसी विशिष्ट समस्या तक सीमित करने के लिए इसे पर्याप्त विवरण के साथ संपादित करें। एक साथ कई अलग-अलग प्रश्न पूछने से बचें। इस प्रश्न को स्पष्ट करने में मदद के लिए पेज कैसे पूछें।"

जैसा कि नीचे उल्लेख किया गया है, एक पर्याप्त उत्तर दिया गया है जो साबित करता है कि एक है और यह प्रदान करने के लिए पर्याप्त आसान है।


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

19
यहां तक ​​कि अगर यह एक 30 लाइन, एक लाइनर है? मैं लंबी श्रृंखलाओं का शौकीन नहीं हूं।
user447607

1
इसके अलावा, मैं यहां जो कुछ भी देख रहा हूं वह एक साक्षात्कार के लिए उपयुक्त प्रतिक्रिया है। यह केवल "राय" है जो मायने रखती है।
user447607

1
शैक्षिक रूप से, इस सवाल ने मुझे भविष्य के साक्षात्कार में भी कुछ गिरावट से बचाया, @slim ने वास्तव में इसे रद्द कर दिया, लेकिन अप्रत्यक्ष रूप से, यह भी बोलता है कि कैसे Microsoft प्रोग्रामिंग भाषाओं ने जावा भाषा को बंद करने के लिए अपने करियर का निर्माण किया, और अंत में jipping द्वारा इसका बदला लिया जाता है लैम्ब्डा एक्सप्रेशन बंद करें और विरोधियों से स्ट्रीम करें , देखते हैं कि जावा भविष्य में
स्ट्रक्चर्स

5
ध्यान दें कि स्ट्रीम केवल कार्यात्मक प्रोग्रामिंग में शक्ति के एक अंश को टैप करते हैं: - /
Thorbjørn Ravn Andersen

जवाबों:


251

दिलचस्प है कि साक्षात्कार प्रश्न फायदे के बारे में पूछता है, नुकसान के बारे में पूछे बिना, क्योंकि दोनों हैं।

धाराएँ अधिक घोषित शैली हैं । या अधिक अभिव्यंजक शैली। यह कैसे किया जाता है, इसका वर्णन करने की तुलना में, कोड में अपने इरादे की घोषणा करना बेहतर माना जा सकता है:

 return people
     .filter( p -> p.age() < 19)
     .collect(toList());

... स्पष्ट रूप से कहते हैं कि आप सूची से मेल खाने वाले तत्वों को फ़िल्टर कर रहे हैं, जबकि:

 List<Person> filtered = new ArrayList<>();
 for(Person p : people) {
     if(p.age() < 19) {
         filtered.add(p);
     }
 }
 return filtered;

कहते हैं "मैं एक पाश कर रहा हूँ"। लूप का उद्देश्य तर्क में गहरा दफन है।

धाराएँ प्रायः मरोड़ होती हैं । इसी उदाहरण से पता चलता है। Terser हमेशा बेहतर नहीं होता है, लेकिन यदि आप एक ही समय में terse और expressive हो सकते हैं, तो बेहतर होगा।

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

धाराएँ कम उत्परिवर्तन को प्रोत्साहित करती हैं । यह कार्यात्मक प्रोग्रामिंग पहलू से संबंधित है - जिस तरह के प्रोग्राम आप स्ट्रीम का उपयोग करते हुए लिखते हैं, उस तरह के प्रोग्राम होते हैं जहाँ आप ऑब्जेक्ट्स को संशोधित नहीं करते हैं।

धाराएँ शिथिल युग्मन को प्रोत्साहित करती हैं । आपके स्ट्रीम-हैंडलिंग कोड को स्ट्रीम के स्रोत या इसके अंतिम समाप्ति विधि को जानने की आवश्यकता नहीं है।

धाराएँ काफी परिष्कृत व्यवहार व्यक्त कर सकती हैं । उदाहरण के लिए:

 stream.filter(myfilter).findFirst();

पहली नज़र में ऐसा लग सकता है मानो यह पूरी धारा को फ़िल्टर करता है, और फिर पहला तत्व लौटाता है। लेकिन वास्तव findFirst()में पूरे ऑपरेशन को चलाता है, इसलिए यह एक आइटम खोजने के बाद कुशलता से बंद हो जाता है।

धाराएँ भविष्य की दक्षता हासिल करने की गुंजाइश प्रदान करती हैं । कुछ लोगों ने बेंचमार्क किया है और पाया है कि इन-मेमोरी Listएस या एरेज़ से सिंगल-थ्रेडेड स्ट्रीम , समान लूप की तुलना में धीमी हो सकती हैं। यह प्रशंसनीय है क्योंकि खेलने में अधिक वस्तुएं और ओवरहेड्स हैं।

लेकिन धाराओं के पैमाने। जावा के साथ-साथ समानांतर धारा संचालन के लिए अंतर्निहित समर्थन, कुछ एपीपी के रूप में स्ट्रीम का उपयोग करके वितरित मानचित्र-कम के लिए कुछ पुस्तकालय हैं, क्योंकि मॉडल फिट बैठता है।

नुकसान?

प्रदर्शन : एक forसरणी के माध्यम से एक लूप ढेर और सीपीयू उपयोग के मामले में बेहद हल्का है। यदि कच्ची गति और मेमोरी थ्रैफ़टनेस एक प्राथमिकता है, तो स्ट्रीम का उपयोग करना बदतर है।

परिचित । यह दुनिया कई भाषा पृष्ठभूमि से अनुभवी प्रक्रियात्मक प्रोग्रामर से भरी हुई है, जिनके लिए लूप परिचित हैं और धाराएं उपन्यास हैं। कुछ परिवेशों में, आप उस कोड को लिखना चाहते हैं जो उस तरह के व्यक्ति से परिचित हो।

संज्ञानात्मक ओवरहेड । इसकी घोषणात्मक प्रकृति के कारण, और जो कुछ भी हो रहा है, उसमें से अमूर्तता बढ़ने के कारण, आपको एक नया मानसिक मॉडल बनाने की आवश्यकता हो सकती है कि कोड निष्पादन से कैसे संबंधित है। वास्तव में आपको केवल यह करने की ज़रूरत है जब चीजें गलत हो जाती हैं, या यदि आपको प्रदर्शन या सूक्ष्म बगों का गहराई से विश्लेषण करने की आवश्यकता है। जब यह "बस काम करता है", यह सिर्फ काम करता है।

डिबगर में सुधार हो रहा है, लेकिन अब भी, जब आप डिबगर में स्ट्रीम कोड के माध्यम से कदम रख रहे हैं, तो यह समकक्ष लूप की तुलना में कठिन काम हो सकता है, क्योंकि एक साधारण लूप चर और कोड स्थानों के बहुत करीब है जो एक पारंपरिक डिबगर के साथ काम करता है।


4
मुझे लगता है कि यह साफ-सुथरा होगा कि धारा-जैसा सामान बहुत अधिक सामान्य होता जा रहा है और अब यह आमतौर पर इस्तेमाल होने वाली भाषाओं में बहुत कुछ दिखाता है जो विशेष रूप से एफपी-उन्मुख नहीं हैं।
केसी

5
यहाँ सूचीबद्ध पेशेवरों और विपक्षों को देखते हुए, मुझे लगता है कि गैर-समालोचना प्रदर्शन भागों में धाराएँ बहुत सरल उपयोगों के अलावा किसी भी चीज़ के लिए इसके लायक नहीं हैं (थोड़ा तर्क अगर / फिर / नहीं तो कई नेस्टेड कॉल या लैम्ब्डा आदि नहीं)
हेनरी काजस अल्स्टैड

1
@HenrikKjusAlstad वह बिल्कुल नहीं है जिसे मैं संवाद करने का इरादा रखता हूं। उत्पादन-ग्रेड कोड के लिए धाराएँ परिपक्व, शक्तिशाली, अभिव्यंजक और पूरी तरह से उपयुक्त हैं।
स्लिम

ओह, मेरा मतलब यह नहीं है कि मैं इसे उत्पादन में उपयोग करूँगा। लेकिन इसके बजाय, मैं धाराओं के बजाय पुराने जमाने के छोरों / आईएफएस आदि को डिफ़ॉल्ट करूंगा, खासकर अगर परिणामस्वरूप धारा जटिल दिखेगी। मुझे यकीन है कि ऐसे उपयोग हैं जहां एक धारा छोरों को हरा देगी और यदि स्पष्टता में है, लेकिन अधिक बार नहीं, तो मुझे लगता है कि यह "बंधा हुआ" है, या कभी-कभी यहां तक ​​कि दूसरे तरीके से भी। इस प्रकार, मैं पुराने तरीकों से चिपके रहने के लिए संज्ञानात्मक उपरि तर्क पर भार डालूँगा।
हेनरिक काजस अल्स्टेड

1
@lijepdam - लेकिन आपके पास अभी भी ऐसा कोड होगा जो कहता है कि "मैं इस सूची पर पुनरावृत्ति कर रहा हूं (यह जानने के लिए लूप के अंदर देखें)", जब "सूची पर पुनरावृत्ति करना" कोड का मूल उद्देश्य नहीं है।
स्लिम

16

एक तरफ सिंथेटिक मज़ा, धाराओं को संभावित रूप से बड़े डेटा सेट के साथ काम करने के लिए डिज़ाइन किया गया है, जबकि सरणियाँ, संग्रह और लगभग हर जावा एसई वर्ग जो पूरी तरह से स्मृति में लागू होता है।

स्ट्रीम का एक नुकसान यह है कि फ़िल्टर, मैपिंग इत्यादि, चेक किए गए अपवादों को फेंक नहीं सकते हैं। यह स्ट्रीम को I / O संचालन के लिए, इंटरमीडिएट के लिए एक खराब विकल्प बनाता है।


7
बेशक, आप अनंत स्रोतों पर भी लूप कर सकते हैं।
स्लिम

लेकिन अगर प्रक्रिया करने के लिए तत्व एक DB में बने हुए हैं, तो आप स्ट्रीम का उपयोग कैसे करते हैं? एक जूनियर देव को केवल स्ट्रीम का उपयोग करने के लिए एक संग्रह में उन सभी को पढ़ने के लिए लुभाया जा सकता है। और यह एक आपदा होगी।
लुलिस मार्टिनेज

2
@LluisMartinez एक अच्छा डीबी क्लाइंट लाइब्रेरी कुछ इस तरह लौटेगा Stream<Row>- या Streamडीबी परिणाम कर्सर संचालन को लपेटकर किसी के स्वयं के कार्यान्वयन को लिखना संभव होगा ।
स्लिम

वह धाराएं चुपचाप अपवादों को नजरअंदाज करती हैं, एक बग है जिसे मैंने हाल ही में काट लिया था। Unintuitive।
xxfelixxx

@xxfelixxx धाराएँ अपवादों को चुपचाप अनदेखा नहीं करती हैं। इसे चलाने का प्रयास करें:Arrays.asList("test", null).stream().forEach(s -> System.out.println(s.length()));
VGR

8
  1. आपने गलत तरीके से महसूस किया: समानांतर ऑपरेशन Streamएस का उपयोग करते हैं , Optionalएस का नहीं ।

  2. आप धाराओं के साथ काम करने के तरीकों को परिभाषित कर सकते हैं: उन्हें मापदंडों के रूप में लेना, उन्हें वापस करना, आदि। आप एक विधि को परिभाषित नहीं कर सकते हैं जो एक पैरामीटर के रूप में लूप लेता है। यह एक जटिल स्ट्रीम ऑपरेशन को एक बार और इसे कई बार उपयोग करने की अनुमति देता है। ध्यान दें कि जावा में एक खामी है: आपके तरीकों someMethod(stream)को स्ट्रीम के विरोध के रूप में बुलाया जाना है stream.someMethod(), इसलिए उन्हें मिश्रण करने से पढ़ने में कठिनाई होती है: संचालन के क्रम को देखने का प्रयास करें

    myMethod2(myMethod(stream.transform(...)).filter(...))

    कई अन्य भाषाएं (C #, कोटलिन, स्काला, आदि) "विस्तार विधियों" के कुछ रूप की अनुमति देती हैं।

  3. यहां तक ​​कि जब आपको केवल अनुक्रमिक संचालन की आवश्यकता होती है, और उन्हें फिर से उपयोग नहीं करना चाहते हैं, ताकि आप या तो स्ट्रीम या लूप का उपयोग कर सकें, धाराओं पर सरल संचालन लूप में काफी जटिल परिवर्तनों के अनुरूप हो सकते हैं।


बताएं 1. क्या वैकल्पिक इंटरफ़ेस का अर्थ वह साधन नहीं है जिसके द्वारा जंजीरों में जकड़े जाते हैं? 3 के बारे में, यह समझ में आता है क्योंकि छोटे सर्कुलेटेड फिल्टर के साथ, विधि केवल निर्दिष्ट घटनाओं के लिए लागू की जाएगी। कुशल। यह समझ में आता है कि मैं यह बता सकता हूं कि उनका उपयोग करने से अतिरिक्त कोड लिखने की आवश्यकता कम हो जाती है जिसे परीक्षण करने की आवश्यकता होगी आदि। समीक्षा करने पर, मुझे यकीन नहीं है कि आप अनुक्रमिक मामले से क्या मतलब है 2.
user447607

1. के Optionalलिए एक विकल्प है null, लेकिन यह समानांतर संचालन के साथ कुछ नहीं करना है। जब तक "अब मुझे एहसास है कि मैं वैकल्पिक के बारे में सोच रहा था" आपके सवाल में केवल nullहैंडलिंग के बारे में बात कर रहा है?
एलेक्सी रोमानोव

मैंने 2 और 3 के क्रम को बदल दिया है और दोनों का थोड़ा विस्तार किया है।
एलेक्सी रोमानोव

6

आप एक अनुक्रम (सरणी, संग्रह, इनपुट, ...) पर लूप करते हैं क्योंकि आप अनुक्रम के तत्वों के लिए कुछ फ़ंक्शन लागू करना चाहते हैं।

धाराएँ आपको अनुक्रम तत्वों पर कार्यों की रचना करने की क्षमता देती हैं और एक ठोस मामले से स्वतंत्र होने के लिए सबसे आम कार्यों (जैसे मैपिंग, फ़िल्टरिंग, ढूंढना, छांटना, एकत्र करना, ...) को लागू करने की अनुमति देती हैं ।

इसलिए ज्यादातर मामलों में कुछ लूपिंग टास्क दिए गए हैं जिन्हें आप स्ट्रीम के इस्तेमाल से कम कोड के साथ व्यक्त कर सकते हैं, यानी आप पठनीयता हासिल करते हैं ।


4
हालांकि, यह सिर्फ पठनीयता नहीं है। कोड आपको लिखना नहीं है, वह कोड है जिसे आपको परीक्षण नहीं करना है।
user447607

3
लगता है कि आप अपने साक्षात्कार के लिए भी अच्छे उत्तर दे रहे हैं
२१

6

मैं कहूंगा कि इसके समांतरकरण का उपयोग करना इतना आसान है। लूप के साथ समानांतर में लाखों प्रविष्टियों पर पुनरावृत्ति करने का प्रयास करें। हम कई सीपी में जाते हैं, तेजी से नहीं; तो बेहतर यह है कि इसे बेहतर तरीके से समानांतर में चलाया जाए, और Streamयह एक हवा है।

मुझे जो बहुत पसंद है, वह वह क्रिया है जो वे पेश करते हैं। यह समझने में बहुत कम समय लगता है कि वे वास्तव में क्या करते हैं और वे इसका विरोध कैसे करते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.