2015-05-04 6 views
39

बस हर किसी की तरह, मैं अभी भी नई जावा 8 स्ट्रीम एपीआई की जटिलताओं (और उन्हें प्यार) सीख रहा हूं। मेरे पास धाराओं के उपयोग से संबंधित एक प्रश्न है। मैं एक सरल उदाहरण प्रदान करूंगा।जावा 8 स्ट्रीम संग्रह में किसी आइटम पर काम कर सकते हैं, और फिर इसे हटा सकते हैं?

जावा स्ट्रीम हमें Collection लेने की अनुमति देता है, और इसके सभी तत्वों की धारा प्राप्त करने के लिए stream() विधि का उपयोग करता है। इसके भीतर, filter(), map(), और forEach() जैसी कई उपयोगी विधियां हैं, जो हमें सामग्री पर लैम्ब्डा संचालन का उपयोग करने की अनुमति देती हैं।

मैं (सरलीकृत) कोड है कि कुछ इस तरह दिखता है:

set.stream().filter(item -> item.qualify()) 
    .map(item -> (Qualifier)item).forEach(item -> item.operate()); 
set.removeIf(item -> item.qualify()); 

विचार जो एक निश्चित क्वालीफायर से मेल सेट में सभी आइटम, की मैपिंग प्राप्त करने के लिए, और फिर उन के माध्यम से संचालित है। ऑपरेशन के बाद, वे कोई और उद्देश्य नहीं देते हैं, और मूल सेट से हटा दिया जाना चाहिए। कोड अच्छी तरह से काम करता है, लेकिन मैं इस भावना को हिला नहीं सकता कि Stream में एक ऑपरेशन है जो एक ही पंक्ति में मेरे लिए ऐसा कर सकता है।

यदि यह जावाडॉक्स में है, तो मैं इसे देख सकता हूं।

क्या एपीआई से ज्यादा परिचित कोई ऐसा कुछ देखता है?

उत्तर

72

आप इस तरह यह कर सकते हैं: हमेशा true रिटर्न

set.removeIf(item -> { 
    if (!item.qualify()) 
     return false; 
    item.operate(); 
    return true; 
}); 

तो item.operate() आप यह बहुत संक्षेप कर सकते हैं।

set.removeIf(item -> item.qualify() && item.operate()); 

हालांकि, मुझे इन दृष्टिकोणों को पसंद नहीं है क्योंकि यह तुरंत स्पष्ट नहीं है कि क्या हो रहा है। निजी तौर पर, मैं इसके लिए for लूप और Iterator का उपयोग करना जारी रखूंगा।

for (Iterator<Item> i = set.iterator(); i.hasNext();) { 
    Item item = i.next(); 
    if (item.qualify()) { 
     item.operate(); 
     i.remove(); 
    } 
} 
+7

+1; धाराओं का उपयोग न करें ताकि आप एक ही पंक्ति पर अपने कोड को फिट कर सकें। लूप अक्सर स्ट्रीमिंग समाधानों की तुलना में अधिक पठनीय होते हैं, भले ही वे अधिक वर्बोज़ हों। – dimo414

+3

मैं 'removeIf()' में राज्य-परिवर्तन कोड डालने में थोड़ा संकोच करता हूं, हालांकि मुझे विश्वास है कि यह सैद्धांतिक रूप से काम करेगा। इसके अतिरिक्त, मेरी स्थिति खुद को कार्यात्मक प्रोग्रामिंग के लिए उधार देती है, इसलिए धाराओं की मेरी ज़रूरत सबकुछ एक ही पंक्ति में पैक करने से परे होती है; लेकिन आपका शुक्रिया। –

+3

लैम्ब्डा अभिव्यक्ति के साथ 'removeIf' का उपयोग करना पूरी तरह से कानूनी है और इसे इस तरह इस्तेमाल किया जाना चाहिए। राज्य परिवर्तन संग्रह एपीआई धारा का हिस्सा नहीं है। – hussachai

1

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

+0

मैं इसके बारे में सोच रहा हूं, लेकिन मेरे वास्तविक (अनुचित) कार्यान्वयन के लिए, धाराएं बहुत बड़ी हो सकती हैं। मैं इसे आम तौर पर चार से आठ कोर मशीनों पर चला रहा हूं; इसलिए जावा के स्ट्रीम एपीआई के युवाओं के बावजूद मुझे अभी तक आश्वस्त नहीं है कि इटेटरेटर्स एक लाभ होगा। समानांतर() 'यहां एक उद्धारक हो सकता है। तत्काल प्रतिक्रिया के लिए धन्यवाद, यद्यपि! लूप के लिए उपयोग करने के लिए –

5

एक लाइन नहीं है, लेकिन हो सकता है आप partitioningBy कलेक्टर का उपयोग कर सकता:

Map<Boolean, Set<Item>> map = 
    set.stream() 
     .collect(partitioningBy(Item::qualify, toSet())); 

map.get(true).forEach(i -> ((Qualifier)i).operate()); 
set = map.get(false); 

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

अन्यथा मुझे लगता है कि आपका दृष्टिकोण अपेक्षाकृत ठीक है।

2

आप वास्तव में क्या करना चाहते हैं अपने सेट को विभाजित करना है। दुर्भाग्यवश जावा 8 विभाजन में टर्मिनल "संग्रह" विधि के माध्यम से केवल संभव है।

// test data set 
Set<Integer> set = ImmutableSet.of(1, 2, 3, 4, 5); 
// predicate separating even and odd numbers 
Predicate<Integer> evenNumber = n -> n % 2 == 0; 

// initial set partitioned by the predicate 
Map<Boolean, List<Integer>> partitioned = set.stream().collect(Collectors.partitioningBy(evenNumber)); 

// print even numbers 
partitioned.get(true).forEach(System.out::println); 
// do something else with the rest of the set (odd numbers) 
doSomethingElse(partitioned.get(false)) 

अपडेट किया गया::

कोड की

स्काला संस्करण ऊपर

val set = Set(1, 2, 3, 4, 5) 
val partitioned = set.partition(_ % 2 == 0) 
partitioned._1.foreach(println) 
doSomethingElse(partitioned._2)` 
+0

आह, उम्मीद है कि वे इन दिनों में से एक "'EEAndAndRemove' विधि" लागू करेंगे। मुझे नहीं लगता कि मेरा कोड कोई स्पष्ट, या कोई तेज़ होगा, अगर मैंने ऐसा किया। सहायता के लिए धनयवाद! –

+0

आश्चर्य की बात है कि आपको इस तरह के विशिष्ट तरीकों की आवश्यकता नहीं है। स्कैला में एक ही कोड बहुत अधिक समझ में आता है (ऊपर देखें)। –

1

अगर मैं सही ढंग से अपने प्रश्न समझ में:

set = set.stream().filter(item -> { 
    if (item.qualify()) { 
     ((Qualifier) item).operate(); 
     return false; 
    } 
    return true; 
}).collect(Collectors.toSet()); 
0

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

आप स्ट्रीम के साथ धारा के स्रोत से तत्वों को हटा नहीं सकते हैं। से Javadoc:

अधिकांश धारा संचालन मानकों कि उपयोगकर्ता द्वारा निर्दिष्ट व्यवहार का वर्णन ..... सही व्यवहार, व्यवहार में हुए इन मानकों को बनाए रखने के लिए स्वीकार करते हैं:

  • गैर दखल होना चाहिए (वे करते हैं स्ट्रीम स्रोत को संशोधित नहीं करें); और
  • ज्यादातर मामलों में स्टेटलेस होना चाहिए (उनका परिणाम किसी भी राज्य पर निर्भर नहीं होना चाहिए जो स्ट्रीम पाइपलाइन के निष्पादन के दौरान बदल सकता है)।
-3
user.getSongs() 
    .stream() 
    .filter(song -> song.getSinger().getId() != singerId) // Only those songs where singer ID doesn't match 
    .forEach(song -> user.getSongs().remove(song)); // Then remove them 
0

मैं जब धाराओं, शीर्ष जवाब में कहा गया है का उपयोग करते हुए पॉल स्पष्टता चिंता को देखते हैं। शायद समेकित चर जोड़ना थोड़ा सा इरादा स्पष्ट करता है।

set.removeIf(item -> { 
    boolean removeItem=item.qualify(); 
    if (removeItem){ 
    item.operate(); 
    } 
    return removeItem; 
}); 
संबंधित मुद्दे