2015-09-02 15 views
12

मान लें कि मैं वस्तुओं के संग्रह पर पुन: प्रयास करना चाहता हूं।लैम्ब्डा अभिव्यक्तियों और बेनामी वर्गों के बीच कार्यान्वयन अंतर/अनुकूलन

List<String> strmap = ... 
//Without lambdas 
strmap.stream().filter(new Predicate<String>() { 
     public boolean test(String string) { 
      return string.length == 10; 
     } 
}.forEach(new Consumer<String>() { 
     public void accept (String string) { 
      System.out.println("string " + string + " contains exactly 10 characters"); 
     } 
} 
//With lambdas 
strmap.stream() 
     .filter(s -> s.length == 10) 
     .forEach(s -> System.out.println("string " + s + " contains exactly 10 characters"); 

दूसरा उदाहरण (लैम्ब्स के बिना) कैसे काम करता है? प्रत्येक बार जब मैं कोड को कॉल करता हूं, तो एक नया ऑब्जेक्ट (पूर्वानुमान और उपभोक्ता) बनाया जाता है, जावा जैट कंपाइलर लैम्ब्डा अभिव्यक्ति को कितना अनुकूल बना सकता है? एक बेहतर प्रदर्शन के लिए क्या मुझे सभी लैम्बडा को एक चर के रूप में घोषित करना चाहिए और हमेशा केवल एक संदर्भ पास करना चाहिए?

private Predicate<String> length10 = s -> s.length == 10; 
private Consumer<String> printer = s -> { "string " + s + " contains exactly 10 characters"; } 

strmap.stream() 
     .filter(length10) 
     .forEach(printer); 
+3

देखें [यहां] (http://stackoverflow.com/q/27524445/2711488)। और [यह] (http://stackoverflow.com/a/23991339/2711488) लैम्बडा अभिव्यक्तियों के साथ-साथ विधि संदर्भों पर भी लागू होता है। हॉटस्पॉट आंतरिक कक्षाओं के अस्थायी उदाहरणों को अनुकूलित कर सकता है, लेकिन स्टेटलेस लैम्ब्डा अभिव्यक्तियों के लिए पहले स्थान पर कोई अस्थायी उदाहरण नहीं हैं। – Holger

+1

@ होल्गर - अच्छे उत्तर – ZhongYu

उत्तर

6

कैसे दूसरे उदाहरण (lambdas) के बिना काम करता है? प्रत्येक बार जब मैं कोड को कॉल करता हूं, तो एक नया ऑब्जेक्ट (पूर्वानुमान और उपभोक्ता) बनाया जाता है, जावा जैट कंपाइलर लैम्ब्डा अभिव्यक्ति को कितना अनुकूल बना सकता है? एक बेहतर प्रदर्शन के लिए क्या मुझे सभी लैम्बडा को एक चर के रूप में घोषित करना चाहिए और हमेशा केवल एक संदर्भ पास करना चाहिए?

जेआईटी का काम इसे बनाना है ताकि आपको इनमें से किसी के बारे में चिंता न करें। उदाहरण के लिए, जेआईटी (और, मुझे विश्वास है, करेंगे) इसे बनाते हैं ताकि s -> s.length == 10 स्वचालित रूप से स्थैतिक स्थिर हो जाए, इसलिए यह पूरी कक्षा में पुन: उपयोग किया जाता है, न केवल उस उदाहरण के लिए। यह अन्य कक्षाओं में भी पुन: उपयोग किया जा सकता है जो कहीं और उसी लैम्ब्डा का उपयोग करते हैं।

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

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

+3

चूंकि एस -> s.length() == 10' invariant है, यह हमेशा जेआईटी की मदद की आवश्यकता के बिना स्थिर हो जाता है। [यह] (http://stackoverflow.com/q/27524445/2711488) भी व्याख्या मोड पर लागू होता है ... – Holger

+0

मैं कार्यान्वयन निर्दिष्ट लिंक किए गए दस्तावेज़ के माध्यम से पढ़ रहा हूं। AFAICT, एस - लम्बाई() == 10' एक निजी स्थैतिक विधि को कम कर दिया गया है, लेकिन मैं अभी भी इस धारणा के तहत हूं कि जेआईटी लैम्ब्डा मेटाफैक्टरी को लागू करता है जो यह तय करता है कि इसे इंटरफ़ेस उदाहरण में कैसे परिवर्तित किया जाए? –

+2

नहीं, ['LambdaMetafactory'] (http://docs.oracle.com/javase/8/docs/api/?java/lang/invoke/LambdaMetafactory.html) एक साधारण जावा क्लास है जो अच्छी तरह से बाइटकोड उत्पन्न करती है अज्ञात एएसएम पुस्तकालय। जब आप लैम्ब्डा अभिव्यक्ति पहली बार तत्काल हो जाते हैं तो आप जावा डीबगर का उपयोग करके भी इसके माध्यम से कदम उठा सकते हैं। लेकिन 'invokedynamic' निर्देश कैसे काम करता है, इसके बाद के बाद के निष्पादन उस पहले आमंत्रण के परिणाम का उपयोग करेंगे जो या तो स्थिर या फैक्ट्री विधि/कन्स्ट्रक्टर आमंत्रण के लिए एक हैंडल है। – Holger

संबंधित मुद्दे