एरण के उत्तर ने दो-आरजी और तीन-आरजी संस्करण के बीच के अंतरों का वर्णन किया reduce
है कि पूर्व कम हो Stream<T>
जाता है T
जबकि बाद में कम हो Stream<T>
जाता है U
। हालांकि, यह वास्तव में जब कम करने के Stream<T>
लिए अतिरिक्त combiner समारोह की आवश्यकता की व्याख्या नहीं की U
।
स्ट्रीम एपीआई के डिजाइन सिद्धांतों में से एक यह है कि एपीआई को अनुक्रमिक और समानांतर धाराओं के बीच अंतर नहीं होना चाहिए, या दूसरा रास्ता नहीं होना चाहिए, एक विशेष एपीआई को स्ट्रीम को क्रमिक रूप से या समानांतर में सही ढंग से चलने से नहीं रोकना चाहिए। यदि आपके लैम्ब्डा में सही गुण हैं (साहचर्य, गैर-हस्तक्षेप, आदि) एक धारा क्रमिक रूप से चलती है या समानांतर में समान परिणाम देना चाहिए।
आइए सबसे पहले कमी के दो-arg संस्करण पर विचार करें:
T reduce(I, (T, T) -> T)
अनुक्रमिक कार्यान्वयन सीधा है। I
परिणाम देने के लिए पहचान मूल्य शून्य धारा तत्व के साथ "संचित" है। यह परिणाम पहली स्ट्रीम तत्व के साथ एक और परिणाम देने के लिए जमा होता है, जो बदले में दूसरी स्ट्रीम तत्व के साथ जमा होता है, और आगे। अंतिम तत्व जमा होने के बाद, अंतिम परिणाम वापस आ जाता है।
धारा को खंडों में विभाजित करके समानांतर कार्यान्वयन शुरू होता है। प्रत्येक खंड को मेरे द्वारा वर्णित अनुक्रमिक फैशन में अपने स्वयं के धागे द्वारा संसाधित किया जाता है। अब, यदि हमारे पास एन थ्रेड्स हैं, तो हमारे पास एन मध्यवर्ती परिणाम हैं। इन्हें एक परिणाम तक कम करने की आवश्यकता है। चूंकि प्रत्येक मध्यवर्ती परिणाम टाइप टी का है, और हमारे पास कई हैं, हम एक ही संचायक फ़ंक्शन का उपयोग उन एन मध्यवर्ती परिणामों को एक एकल परिणाम तक कम करने के लिए कर सकते हैं।
अब आइए एक काल्पनिक द्वि-आर्गन कमी ऑपरेशन पर विचार करें जो कम हो Stream<T>
जाता है U
। अन्य भाषाओं में, इसे "फोल्ड" या "फोल्ड-लेफ्ट" ऑपरेशन कहा जाता है, इसलिए मैं इसे यहां कहूंगा। ध्यान दें कि यह जावा में मौजूद नहीं है।
U foldLeft(I, (U, T) -> U)
(ध्यान दें कि पहचान मूल्य I
U प्रकार का है)
का अनुक्रमिक संस्करण foldLeft
केवल अनुक्रमिक संस्करण की तरह है reduce
सिवाय इसके कि मध्यवर्ती मान टाइप T के बजाय U प्रकार के हैं। लेकिन यह अन्यथा समान है। (एक काल्पनिक foldRight
ऑपरेशन समान होगा सिवाय इसके कि ऑपरेशन बाएं-से-दाएं के बजाय दाएं-बाएं किया जाएगा।)
अब के समानांतर संस्करण पर विचार करें foldLeft
। खंडों में धारा को विभाजित करके शुरू करते हैं। इसके बाद, हम एन थ्रेड्स में से प्रत्येक को अपने सेगमेंट में टी मानों को एन यू के मध्यवर्ती मूल्यों में घटा सकते हैं। अब क्या? U प्रकार के एकल परिणाम के नीचे U के प्रकार के N मान कैसे मिलते हैं?
क्या गायब है एक और फ़ंक्शन है जो टाइप यू के एक ही परिणाम में यू के कई मध्यवर्ती परिणामों को जोड़ता है । यदि हमारे पास एक फ़ंक्शन है जो दो यू मूल्यों को एक में जोड़ता है, तो यह किसी भी संख्या के मूल्यों को एक से कम करने के लिए पर्याप्त है - जैसे ऊपर मूल कमी। इस प्रकार, कमी ऑपरेशन जो एक अलग प्रकार के परिणाम देता है उसे दो कार्यों की आवश्यकता होती है:
U reduce(I, (U, T) -> U, (U, U) -> U)
या, जावा सिंटैक्स का उपयोग कर:
<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
सारांश में, एक अलग परिणाम प्रकार के समानांतर कमी करने के लिए, हमें दो कार्यों की आवश्यकता है: एक जो कि यू तत्वों को मध्यवर्ती यू मानों में जमा करता है, और एक दूसरा जो एक यू परिणाम में मध्यवर्ती यू मूल्यों को जोड़ता है। यदि हम प्रकार स्विच नहीं कर रहे हैं, तो यह पता चलता है कि संचायक फ़ंक्शन कॉम्बिनर फ़ंक्शन के समान है। इसलिए एक ही प्रकार की कमी में केवल संचायक कार्य होता है और एक अलग प्रकार में कमी के लिए अलग संचयकर्ता और कॉम्बिनर फ़ंक्शन की आवश्यकता होती है।
अंत में, जावा प्रदान नहीं करता है foldLeft
और foldRight
संचालन नहीं करता है क्योंकि वे परिचालन के एक विशेष आदेश का पालन करते हैं जो स्वाभाविक रूप से अनुक्रमिक है। यह डिज़ाइन सिद्धांत के साथ टकराव प्रदान करता है जो एपीआई प्रदान करने के ऊपर है जो समान रूप से अनुक्रमिक और समानांतर संचालन का समर्थन करता है।