जब भी जावा अच्छा अभ्यास संभव हो तो लैम्ब्डा अभिव्यक्ति का उपयोग करना है?


52

मैंने हाल ही में जावा 8 में पेश की गई लैम्ब्डा अभिव्यक्ति में महारत हासिल की है। मुझे लगता है कि जब भी मैं एक कार्यात्मक इंटरफ़ेस का उपयोग कर रहा हूं, तो मैं एक वर्ग बनाने के बजाय हमेशा एक लैम्ब्डा अभिव्यक्ति का उपयोग करता हूं जो कार्यात्मक इंटरफ़ेस को लागू करता है।

क्या यह अच्छा अभ्यास माना जाता है? या क्या उनकी स्थितियां एक कार्यात्मक इंटरफ़ेस के लिए एक लैम्ब्डा का उपयोग करना उचित नहीं है?


122
इस सवाल पर "क्या तकनीक एक्स का उपयोग कर रही है जब भी संभव अच्छा अभ्यास" एकमात्र सही उत्तर है "नहीं, जब भी संभव हो तकनीक एक्स का उपयोग करें, लेकिन जब भी होश में हो"
डॉक ब्राउन

लैंबडा (जो कि अनाम है) बनाम कुछ अन्य प्रकार के कार्यात्मक कार्यान्वयन (जैसे एक विधि संदर्भ) का उपयोग करने का विकल्प वास्तव में एक दिलचस्प सवाल है। मुझे कुछ दिनों पहले जोश बलोच से मिलने का अवसर मिला था, और यह उन बिंदुओं में से एक था जिसके बारे में उन्होंने बात की थी। उसने जो कहा उससे मुझे समझ में आया कि वह इस सटीक प्रश्न से निपटने के लिए प्रभावी जावा के अगले संस्करण में एक नया आइटम जोड़ने की योजना बना रहा है ।
डैनियल प्राइडेन

@DocBrown यह एक जवाब होना चाहिए, एक टिप्पणी नहीं।
gnasher729

1
@ gnasher729: निश्चित रूप से नहीं।
डॉक्टर ब्राउन

जवाबों:


116

ऐसे कई मानदंड हैं जो आपको एक लंबोदा का उपयोग नहीं करने पर विचार करना चाहिए:

  • आकार बड़ा लंबोदर जितना बड़ा हो जाता है, उतना ही मुश्किल होता है कि वह अपने आसपास के तर्क का पालन कर सके।
  • पुनरावृत्ति बार-बार तर्क के लिए एक नामित फ़ंक्शन बनाने के लिए बेहतर है, हालांकि यह बहुत सरल लैम्ब्डा को दोहराने के लिए ठीक है जो अलग-अलग फैले हुए हैं।
  • नामकरण यदि आप एक महान शब्दार्थ नाम के बारे में सोच सकते हैं, तो आपको इसके बजाय इसका उपयोग करना चाहिए, क्योंकि यह आपके कोड में बहुत स्पष्टता जोड़ता है। मैं नाम की बात नहीं कर रहा हूँ priceIsOver100x -> x.price > 100उस नाम के समान ही स्पष्ट है। मेरा मतलब है isEligibleVoterकि ऐसे नाम जो स्थितियों की एक लंबी सूची को प्रतिस्थापित करते हैं।
  • घोंसले के शिकार नेमदास वास्तव में वास्तव में पढ़ने के लिए कठिन हैं।

ओवरबोर्ड मत जाओ। याद रखें, सॉफ्टवेयर आसानी से बदल जाता है। जब संदेह हो, तो इसे दोनों तरीके से लिखें और देखें कि कौन सा पढ़ना आसान है।


1
लैम्ब्डा के माध्यम से संसाधित किए जाने वाले डेटा की मात्रा पर विचार करना भी महत्वपूर्ण है, क्योंकि लैम्ब्डा डेटा प्रोसेसिंग की कम मात्रा में अक्षम हैं। वे वास्तव में बड़े डेटा सेट के समानांतर चमकते हैं।
क्रेग आर 8806

1
@ CraigR8806 मुझे नहीं लगता कि प्रदर्शन यहां चिंता का विषय है। एक अनाम फ़ंक्शन का उपयोग करना या कार्यात्मक इंटरफ़ेस का विस्तार करने वाला वर्ग बनाना समान प्रदर्शन बुद्धिमान होना चाहिए। प्रदर्शन विचार तब आते हैं जब आप धाराओं / उच्च-क्रम-फ़ंक्शंस एपीआई को अनिवार्य शैली के लूप का उपयोग करने के बारे में बात करते हैं, लेकिन इस प्रश्न में हम अलग-अलग वाक्यविन्यास के साथ दोनों मामलों में कार्यात्मक इंटरफेस का उपयोग कर रहे हैं।
पुहलेन २ ''१

17
"हालांकि यह बहुत ही सरल लैंबडों को दोहराने के लिए ठीक है जो अलग-अलग फैले हुए हैं" केवल अगर वे जरूरी नहीं कि एक साथ बदलते हैं। वे तो चाहिए सब हो ही तर्क आपका कोड सही होने के लिए, आप उन सभी वास्तव में एक ही विधि बनाना चाहिए ताकि परिवर्तन केवल एक ही स्थान पर किए जाने की जरूरत है।
jpmc26

कुल मिलाकर यह एक बहुत अच्छा जवाब है। एक विधि संदर्भ के उपयोग को लंबोदर के विकल्प के रूप में उल्लेख करना केवल इस उत्तर में मेरे द्वारा देखे जाने वाले छेद को पैच करना होगा।
मॉर्गन

3
जब संदेह हो, तो इसे लिखने के दोनों तरीके और किसी और से पूछें जो कोड को बनाए रखता है जो पढ़ना आसान है।
corsiKa

14

निर्भर करता है। जब भी आप अपने आप को विभिन्न स्थानों में एक ही लैम्ब्डा का उपयोग करते हुए पाते हैं, तो आपको इंटरफ़ेस को लागू करने वाले वर्ग को लागू करने पर विचार करना चाहिए। लेकिन अगर आपने एक अनाम आंतरिक वर्ग का उपयोग किया है, तो मुझे लगता है कि एक लंबोदर कहीं बेहतर है।


6
एक विधि संदर्भ का उपयोग करने की संभावना को मत भूलना! ओरेकल ने जोड़ा है (और जावा 9 में और भी अधिक जोड़ रहा है) बिल्कुल उसी कारण से सभी जगह स्थिर तरीके और डिफ़ॉल्ट तरीके।
जोर्ग डब्ल्यू मित्तग

13

मैं कार्ल बेवफेल्ट के उत्तर का समर्थन करता हूं, लेकिन एक संक्षिप्त रूप प्रदान करना चाहता हूं।

  • कुछ IDE के संघर्ष को लैम्बडा के अंदर स्कोप के साथ डिबग करना , और लैम्बडा के संदर्भ में सदस्य चर को प्रदर्शित करने के लिए संघर्ष करना। हालांकि उम्मीद है कि यह स्थिति लाइन को बदल देगी, यह किसी और के कोड को बनाए रखने के लिए कष्टप्रद हो सकता है जब यह लैम्ब्डा से अटे पड़े हों।

.NET का निश्चित रूप से सच है। जरूरी नहीं कि मुझे लंबोदर से बचना चाहिए, लेकिन अगर मैं इसके बजाय कुछ और करूं तो मुझे कोई ग्लानि महसूस नहीं होगी।
user1172763

3
अगर ऐसा है तो आप गलत आईडीई का उपयोग कर रहे हैं। IntelliJ और Netbeans दोनों उस विशेष क्षेत्र में बहुत अच्छा करते हैं।
डेविड फ़ॉस्टर

1
@ user1172763 विज़ुअल स्टूडियो में, यदि आप सदस्य चर देखना चाहते हैं, तो मैंने पाया है कि आप लंबोदर के संदर्भ तक कॉल स्टैक तक यात्रा कर सकते हैं।
ज़ेव स्पिट्ज

6

परिक्षेत्र के स्थानीय चर तक पहुँच

कार्ल बेवफेल्ट द्वारा स्वीकृत उत्तर सही है। मैं एक और भेद जोड़ सकता हूं:

  • क्षेत्र

एक वर्ग के अंदर एक विधि के अंदर निहित लैम्ब्डा कोड किसी भी प्रभावी ढंग से उस विधि और वर्ग के भीतर पाए जाने वाले अंतिम चर तक पहुंच सकता है ।

एक वर्ग बनाना जो कार्यात्मक इंटरफ़ेस को लागू करता है, आपको कॉलिंग की स्थिति में ऐसी सीधी पहुंच नहीं देता है।

जावा ट्यूटोरियल को उद्धृत करने के लिए (जोर दें):

स्थानीय और अनाम वर्गों की तरह, लैम्ब्डा अभिव्यक्ति चर पर कब्जा कर सकते हैं; उनके पास एन्क्लेविंग स्कोप के स्थानीय चर तक समान पहुंच है । हालांकि, स्थानीय और अनाम कक्षाओं के विपरीत, लैम्ब्डा के भावों में कोई भी छायांकन समस्या नहीं है (अधिक जानकारी के लिए शैडोइंग देखें)। लैम्ब्डा एक्सप्रेशंस लेक्सिकली स्कोप हैं। इसका मतलब यह है कि वे किसी सुपरपाइप से किसी भी नाम को विरासत में नहीं लेते हैं या नए स्तर की डांट पेश करते हैं। एक लंबोदर अभिव्यक्ति में घोषणाओं की व्याख्या की जाती है जैसे कि वे संलग्न वातावरण में हैं।

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

देख:


4

यह नाइट-पिकिंग हो सकता है, लेकिन अन्य उत्तरों में किए गए सभी उत्कृष्ट बिंदुओं में, मैं जोड़ूंगा:

जब संभव हो तो विधि संदर्भ देखें । की तुलना करें:

employees.stream()
         .map(Employee::getName)
         .forEach(System.out::println);

बनाम

employees.stream()
         .map(employee -> employee.getName())
         .forEach(employeeName -> System.out.println(employeeName));

एक विधि संदर्भ का उपयोग करके आप लैम्ब्डा के तर्क (रों), जो आमतौर पर अनावश्यक है और / या की तरह आलसी नाम की ओर जाता है नाम के लिए की ज़रूरत नहीं पड़ती eया x


0

मैट मैकहेनरी के उत्तर पर निर्माण, लैम्ब्डा और विधि संदर्भों के बीच एक संबंध हो सकता है जहां लैम्बडा को विधि संदर्भों की एक श्रृंखला के रूप में फिर से लिखा जा सकता है। उदाहरण के लिए:

employees.stream()
         .forEach(employeeName -> System.out.println(employee.getName()));

बनाम

employees.stream()
         .map(Employee::getName)
         .forEach(System.out::println);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.