हर बार निष्पादित होने पर ढेर पर एक लैम्बडा अभिव्यक्ति एक वस्तु बनाता है?


182

जब मैं जावा 8 की नई वाक्य रचना चीनी का उपयोग कर एक संग्रह पर पुनरावृति करता हूं, जैसे कि

myStream.forEach(item -> {
  // do something useful
});

क्या यह 'पुराने वाक्यविन्यास' स्निपेट के बराबर नहीं है?

myStream.forEach(new Consumer<Item>() {
  @Override
  public void accept(Item item) {
    // do something useful
  }
});

क्या इसका मतलब यह है कि Consumerहर बार जब मैं एक संग्रह पर पुनरावृति करता हूं, तो एक नई अनाम वस्तु बनाई जाती है? यह कितना ढेर स्थान लेता है? इसका क्या प्रदर्शन निहितार्थ है? क्या इसका मतलब है कि मुझे बड़ी बहु-स्तरीय डेटा संरचनाओं पर पुनरावृत्ति करते समय लूप के लिए पुरानी शैली का उपयोग करना चाहिए?


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

जवाबों:


158

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

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

अधिक विवरण के लिए आप इस उत्तर को पढ़ सकते हैं । वहां, मैंने न केवल अधिक विस्तृत विवरण दिया, बल्कि वर्तमान व्यवहार का निरीक्षण करने के लिए कोड का परीक्षण भी किया।


यह Java® लैंग्वेज स्पेसिफिकेशन, चैप्टर “ 15.27.4 द्वारा कवर किया गया है लंबोदर एक्सप्रेस का रन-टाइम मूल्यांकन

संक्षेप:

ये नियम जावा प्रोग्रामिंग भाषा के कार्यान्वयन में लचीलापन प्रदान करने के लिए हैं, इसमें:

  • हर मूल्यांकन पर एक नई वस्तु आवंटित नहीं की जानी चाहिए।

  • विभिन्न लैम्ब्डा अभिव्यक्तियों द्वारा निर्मित वस्तुओं को विभिन्न वर्गों (यदि शरीर समान हैं, उदाहरण के लिए) की आवश्यकता नहीं है।

  • मूल्यांकन द्वारा उत्पादित प्रत्येक वस्तु एक ही वर्ग से संबंधित नहीं है (कैप्चर किए गए स्थानीय चर इनलेट किए जा सकते हैं, उदाहरण के लिए)।

  • यदि एक "मौजूदा उदाहरण" उपलब्ध है, तो इसे पिछले लैम्ब्डा मूल्यांकन में नहीं बनाया गया है (इसे उदाहरण के लिए, संलग्नक वर्ग के प्रारंभ के दौरान आवंटित किया गया हो सकता है)।


24

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

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

यहाँ विषय पर एक अच्छा, सुलभ में गहराई से लेख है:

http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood


0

आप forEachविधि के लिए एक नया उदाहरण दे रहे हैं । हर बार जब आप करते हैं कि आप एक नई वस्तु बनाते हैं, लेकिन हर लूप पुनरावृत्ति के लिए नहीं। forEachलूप के साथ किए जाने तक समान 'कॉलबैक' ऑब्जेक्ट उदाहरण का उपयोग करके विधि के अंदर पुनरावृत्ति की जाती है ।

तो लूप द्वारा उपयोग की जाने वाली मेमोरी संग्रह के आकार पर निर्भर नहीं करती है।

क्या यह 'पुराने सिंटैक्स' स्निपेट के बराबर नहीं है?

हाँ। इसमें बहुत कम स्तर पर मामूली अंतर होता है लेकिन मुझे नहीं लगता कि आपको उनकी परवाह करनी चाहिए। लांबा अभिव्यक्तियाँ अनाम कक्षाओं के बजाय इनवॉकेन्डेमिक सुविधा का उपयोग करती हैं।


क्या आपके पास इसका उल्लेख करने वाला कोई दस्तावेज है? यह काफी दिलचस्प अनुकूलन है।
ए। राम

धन्यवाद, लेकिन क्या होगा अगर मेरे पास संग्रह के संग्रह का संग्रह है, उदाहरण के लिए जब एक पेड़-डाटासट्रक्चर पर गहराई-पहली खोज कर रहा है?
बैस्टियन Voigt

2
@ ए। रामा क्षमा करें, मैं अनुकूलन नहीं देखता। यह लैम्बदास के साथ या बिना और फॉरएप लूप के साथ समान है।
अकलू

1
यह वास्तव में समान नहीं है, लेकिन फिर भी प्रति घोंसले के स्तर पर सबसे अधिक एक वस्तु की जरूरत किसी भी एक समय पर होगी, जो नगण्य है। आंतरिक लूप का प्रत्येक नया पुनरावृत्ति एक नई वस्तु का निर्माण करेगा, जो संभवतः बाहरी लूप से वर्तमान वस्तु को कैप्चर कर रहा है। यह कुछ GC दबाव बनाता है, लेकिन फिर भी वास्तव में चिंता करने की कोई बात नहीं है।
मार्को टोपोलनिक

4
@aalku: " हर बार जब आप ऐसा करते हैं कि आप एक नई वस्तु बनाते हैं ": होल्गर के इस उत्तर के अनुसार नहीं और ब्रायन गोएत्ज़ की यह टिप्पणी
Lii
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.