मुझे लूप के बजाय "कार्यात्मक संचालन" का उपयोग क्यों करना चाहिए?


39
for (Canvas canvas : list) {
}

NetBeans ने मुझे "कार्यात्मक संचालन" का उपयोग करने का सुझाव दिया:

list.stream().forEach((canvas) -> {
});

लेकिन यह क्यों पसंद किया जाता है ? कुछ भी हो, पढ़ना और समझना कठिन है। आप कॉल कर रहे हैं stream(), फिर forEach()पैरामीटर के साथ एक लैम्ब्डा अभिव्यक्ति का उपयोग कर रहे हैं canvas। मैं नहीं देखता कि forपहली स्निपेट में लूप की तुलना में कोई भी अच्छा कैसे है ।

जाहिर है मैं केवल सौंदर्यशास्त्र से बाहर बोल रहा हूं। शायद यहाँ एक तकनीकी लाभ है जो मुझे याद आ रहा है। यह क्या है? मुझे इसके बजाय दूसरी विधि का उपयोग क्यों करना चाहिए?



15
आपके विशेष उदाहरण में, यह पसंद नहीं किया जाएगा।
रॉबर्ट हार्वे

1
जब तक एकमात्र ऑपरेशन ही एक एकल है, मैं आपसे सहमत हूं। जैसे ही आप पाइपलाइन में अन्य संचालन जोड़ते हैं, या आप आउटपुट अनुक्रम का उत्पादन करते हैं, तब स्ट्रीम-एप्रोच बेहतर हो जाता है।
जैक्सबी 21

@RobertHarvey यह नहीं होगा? क्यों नहीं?
सारा

@RobertHarvey अच्छी तरह से मैं सहमत हूं कि स्वीकृत उत्तर वास्तव में दिखाता है कि अधिक जटिल मामलों के लिए फॉर-वर्जन पानी से कैसे बह जाता है, लेकिन मैं नहीं देखता कि तुच्छ मामले में "जीत" के लिए क्यों। आप कहते हैं कि यह स्व-स्पष्ट है, लेकिन मैं इसे नहीं देखता, इसलिए मैंने पूछा।
सारा

जवाबों:


45

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

आपका उदाहरण बहुत व्यावहारिक नहीं है। ओरेकल साइट से निम्नलिखित कोड पर विचार करें ।

List<Transaction> groceryTransactions = new Arraylist<>();
for(Transaction t: transactions){
  if(t.getType() == Transaction.GROCERY){
    groceryTransactions.add(t);
  }
}
Collections.sort(groceryTransactions, new Comparator(){
  public int compare(Transaction t1, Transaction t2){
    return t2.getValue().compareTo(t1.getValue());
  }
});
List<Integer> transactionIds = new ArrayList<>();
for(Transaction t: groceryTransactions){
  transactionsIds.add(t.getId());
}

धाराओं का उपयोग करके लिखा जा सकता है:

List<Integer> transactionsIds = 
    transactions.stream()
                .filter(t -> t.getType() == Transaction.GROCERY)
                .sorted(comparing(Transaction::getValue).reversed())
                .map(Transaction::getId)
                .collect(toList());

दूसरा विकल्प बहुत अधिक पठनीय है। इसलिए जब आपने आंशिक प्रसंस्करण करते हुए छोरों या विभिन्न छोरों को घोंसला बनाया है, तो यह स्ट्रीम / लैम्ब्डा एपीआई उपयोग के लिए बहुत अच्छा उम्मीदवार है।


5
वहाँ की तरह अनुकूलन तकनीकों हैं नक्शा संलयन ( stream.map(f).map(g)stream.map(f.andThen(g))) निर्माण / संलयन को कम (धारा जब एक विधि में एक धारा का निर्माण और फिर इसे एक और तरीका है जो यह की खपत करने के लिए पारित करने, संकलक समाप्त कर सकते हैं) और धारा संलयन (जो कई धारा ऑप्स फ्यूज कर सकते हैं एक साथ एक एकल लूप लूप में), जो स्ट्रीम ऑपरेशन को और अधिक कुशल बना सकता है। वे जीएचसी हास्केल संकलक में, और कुछ अन्य हास्केल और अन्य कार्यात्मक भाषा संकलक में भी कार्यान्वित किए जाते हैं, और स्काला के लिए प्रायोगिक अनुसंधान कार्यान्वयन हैं।
जोर्ग डब्ल्यू मित्तग

प्रदर्शन संभवतः एक कारक नहीं है जब कार्यात्मक बनाम लूप पर विचार किया जा सकता है क्योंकि निश्चित रूप से संकलक एक कार्यात्मक संचालन के लिए लूप से रूपांतरण कर सकता है / सकती है यदि नेटबिन कर सकता है और यह इष्टतम पथ होने के लिए निर्धारित है।
रियान

मैं असहमत हूं कि दूसरा अधिक पठनीय है। यह पता लगाने में थोड़ा समय लगता है कि क्या हो रहा है। क्या यह दूसरा तरीका करने के लिए एक प्रदर्शन लाभ है क्योंकि अन्यथा मैं इसे नहीं देखता हूं?
बोक मैकडोनाग

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

16

कार्यात्मक स्ट्रीमिंग एपीआई का उपयोग करने का एक और फायदा यह है कि यह कार्यान्वयन विवरण को छुपाता है। यह केवल वर्णन करता है कि क्या किया जाना चाहिए, कैसे नहीं। यह लाभ स्पष्ट हो जाता है जब परिवर्तन को देखते हुए, एकल थ्रेड से समानांतर कोड निष्पादन के लिए बदलना पड़ता है। बस .stream()करने के लिए बदल जाते हैं .parallelStream()


13

कुछ भी हो, पढ़ना और समझना कठिन है।

यह बहुत व्यक्तिपरक है। मुझे पढ़ने और समझने में दूसरा संस्करण बहुत आसान लगता है। यह मेल खाता है कि अन्य भाषाएं (जैसे कि रूबी, स्मॉलटॉक, क्लोज़र, Io, Ioke, Seph) कैसे करती हैं, इसे समझने के लिए कम अवधारणाओं की आवश्यकता होती है (यह किसी भी अन्य की तरह एक सामान्य विधि कॉल है, जबकि पहला उदाहरण विशेष वाक्यविन्यास है)।

अगर कुछ भी, यह परिचित का मामला है।


6
हाँ यह सच है। लेकिन यह मेरे लिए एक जवाब की तुलना में अधिक टिप्पणी की तरह लग रहा है।
ओमेगा

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