Java में lambda forEach () से लौटें


95

मैं forEach()मेमने की अभिव्यक्ति की संभावनाओं की खोज करने के लिए लैंबडा -मैथोड्स के लिए प्रत्येक लूप को बदलने की कोशिश कर रहा हूं । निम्नलिखित संभव प्रतीत होता है:

ArrayList<Player> playersOfTeam = new ArrayList<Player>();      
for (Player player : players) {
    if (player.getTeam().equals(teamName)) {
        playersOfTeam.add(player);
    }
}

लंबोदर के साथ forEach()

players.forEach(player->{if (player.getTeam().equals(teamName)) {playersOfTeam.add(player);}});

लेकिन अगले एक काम नहीं करता है:

for (Player player : players) {
    if (player.getName().contains(name)) {
        return player;
    }
}

लंबोदर के साथ

players.forEach(player->{if (player.getName().contains(name)) {return player;}});

क्या अंतिम पंक्ति के सिंटैक्स में कुछ गड़बड़ है या forEach()विधि से वापस लौटना असंभव है ?


मैं अभी तक लांबडा के आंतरिक लोगों से परिचित नहीं हूं, लेकिन जब मैं खुद से सवाल पूछता हूं: "इससे क्या होगा?", मेरा प्रारंभिक संदेह यह होगा कि यह विधि नहीं है।
गिम्बी

1
@ गिम्बी हां, returnएक स्टेटमेंट के भीतर लैंबडा खुद लैंबडा से लौटता है, जिसे लैम्ब्डा नहीं कहा जाता है। इयान रॉबर्ट्स के उत्तरfindFirst में दिखाए गए अनुसार एक धारा को जल्दी ("शॉर्ट-सर्क्युटिंग") उपयोग करें ।
स्टुअर्ट मार्क्स

जवाबों:


118

returnवहाँ लैम्ब्डा अभिव्यक्ति से बजाय युक्त विधि से लौट रहा है। इसके बजाय forEachआपको filterस्ट्रीम की आवश्यकता है :

players.stream().filter(player -> player.getName().contains(name))
       .findFirst().orElse(null);

यहां filterउन वस्तुओं के लिए स्ट्रीम को प्रतिबंधित किया गया है जो विधेय से मेल खाती हैं, और findFirstफिर Optionalपहले मिलान प्रविष्टि के साथ वापस आती है ।

यह फॉर-लूप दृष्टिकोण की तुलना में कम कुशल लगता है, लेकिन वास्तव में findFirst()शॉर्ट-सर्किट हो सकता है - यह संपूर्ण फ़िल्टर्ड स्ट्रीम उत्पन्न नहीं करता है और फिर इसमें से एक तत्व को निकालता है, बल्कि यह केवल कई तत्वों को फ़िल्टर करता है, ताकि इसे क्रम में किया जा सके पहले मिलान का पता लगाएं। आप findAny()इसके बजाय इसका उपयोग कर सकते हैं findFirst()यदि आप जरूरी नहीं कि (ऑर्डर किए गए) स्ट्रीम से पहला मिलान करने वाले खिलाड़ी को प्राप्त करने के बारे में परवाह करें, लेकिन बस किसी भी मिलान वाले आइटम से। यह बेहतर दक्षता के लिए अनुमति देता है जब समानता शामिल है।


धन्यवाद, यही मैं ढूंढ रहा था! पता लगाने के लिए Java8 में बहुत कुछ नया प्रतीत होता है :)
samutamm

10
उचित, लेकिन मेरा सुझाव है कि आप orElse(null)एक पर उपयोग नहीं करते हैं OptionalOptionalओवरलोडिंग नल (जो NPEP की ओर जाता है) के बजाय एक मूल्य की उपस्थिति या अनुपस्थिति को इंगित करने का एक तरीका प्रदान करना मुख्य बिंदु है। यदि आप इसका उपयोग करते हैं optional.orElse(null)तो अशक्त समस्याओं के सभी वापस खरीदता है। यदि आप कॉलर को संशोधित नहीं कर सकते हैं, तो मैं इसका उपयोग करूंगा और यह वास्तव में अशक्त होने की उम्मीद है।
स्टुअर्ट मार्क्स

1
@StuartMarks वास्तव में, विधि वापसी प्रकार को संशोधित करके Optional<Player>धाराओं के प्रतिमान में फिट होने के लिए एक अधिक प्राकृतिक तरीका होगा। मैं केवल यह दिखाने की कोशिश कर रहा था कि लैम्ब्डा का उपयोग करके मौजूदा व्यवहार की नकल कैसे की जाए।
इयान रॉबर्ट्स

के लिए (भाग भाग: भागों) अगर (? part.isEmpty ()) गलत; मुझे आश्चर्य है कि वास्तव में क्या छोटा है। और साफ़ करना। जावा स्ट्रीम एपीआई ने वास्तव में जावा भाषा और जावा पर्यावरण को नष्ट कर दिया है। 2020 में किसी भी जावा परियोजना में काम करने के लिए दुःस्वप्न
mmm

15

मैं आपको सुझाव देता हूं कि आप पूरी तस्वीर में सबसे पहले जावा 8 को समझने की कोशिश करें, सबसे महत्वपूर्ण बात यह है कि यह आपके लिए स्ट्रीम, लैम्ब्डा और विधि संदर्भ होगा।

आपको लाइन-दर-लाइन आधार पर मौजूदा कोड को जावा 8 कोड में कभी नहीं बदलना चाहिए , आपको सुविधाओं को निकालना चाहिए और उन को बदलना चाहिए।

आपके पहले मामले में मैंने जो पहचाना वह निम्नलिखित है:

  • आप इनपुट संरचना के तत्वों को आउटपुट सूची में जोड़ना चाहते हैं यदि वे कुछ विधेय से मेल खाते हैं।

आइए देखें कि हम ऐसा कैसे करते हैं, हम इसे निम्नलिखित के साथ कर सकते हैं:

List<Player> playersOfTeam = players.stream()
    .filter(player -> player.getTeam().equals(teamName))
    .collect(Collectors.toList());

आप यहाँ क्या कर रहे हैं:

  1. अपनी इनपुट संरचना को एक स्ट्रीम में बदल दें (मैं यहां मान रहा हूं कि यह प्रकार का है Collection<Player>, अब आपके पास ए Stream<Player>
  2. Predicate<Player>अगर यह रखा जाना है, तो हर खिलाड़ी को बूलियन सच में मैपिंग के साथ सभी अवांछित तत्वों को फ़िल्टर करें ।
  3. सूची में परिणामी तत्वों को इकट्ठा करें, एक के माध्यम से Collector, यहां हम मानक पुस्तकालय संग्राहकों में से एक का उपयोग कर सकते हैं, जो है Collectors.toList()

इसमें दो अन्य बिंदु भी शामिल हैं:

  1. इंटरफेस के खिलाफ कोड, इसलिए List<E>ओवर के खिलाफ कोड ArrayList<E>
  2. में प्रकार पैरामीटर के लिए हीरे के अनुमान का उपयोग करें new ArrayList<>(), आप सभी के बाद जावा 8 का उपयोग कर रहे हैं।

अब अपने दूसरे बिंदु पर:

आप फिर से बड़ी तस्वीर को देखे बिना विरासत जावा के कुछ को जावा 8 में बदलना चाहते हैं। इस भाग का जवाब पहले ही @IanRoberts द्वारा दिया जा चुका है , हालाँकि मुझे लगता है कि आपको players.stream().filter(...)...सुझाव देने की ज़रूरत है ।


5

यदि आप बूलियन मान वापस करना चाहते हैं, तो आप कुछ इस तरह का उपयोग कर सकते हैं (फ़िल्टर की तुलना में बहुत तेज़):

players.stream().anyMatch(player -> player.getName().contains(name));


1

आप एक अपवाद भी फेंक सकते हैं:

ध्यान दें:

पठनीयता के लिए धारा के प्रत्येक चरण को नई पंक्ति में सूचीबद्ध किया जाना चाहिए।

players.stream()
       .filter(player -> player.getName().contains(name))
       .findFirst()
       .orElseThrow(MyCustomRuntimeException::new);

यदि आपका तर्क शिथिल "अपवाद संचालित" है जैसे कि आपके कोड में एक स्थान है जो सभी अपवादों को पकड़ता है और यह तय करता है कि आगे क्या करना है। केवल अपवाद संचालित विकास का उपयोग करें जब आप अपने कोड आधार को गुणकों के साथ रखने से बच सकते हैं try-catchऔर इन अपवादों को फेंकना बहुत विशेष मामलों के लिए है जो आप उनसे उम्मीद करते हैं और उन्हें ठीक से संभाला जा सकता है।)

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