CodeGym /Java Blog /अनियमित /जावा में लैम्ब्डा एक्सप्रेशन की व्याख्या। उदाहरणों और कार...
John Squirrels
स्तर 41
San Francisco

जावा में लैम्ब्डा एक्सप्रेशन की व्याख्या। उदाहरणों और कार्यों के साथ। भाग ---- पहला

अनियमित ग्रुप में प्रकाशित
यह लेख किसके लिए है?
  • यह उन लोगों के लिए है जो सोचते हैं कि वे पहले से ही जावा कोर को अच्छी तरह से जानते हैं, लेकिन जावा में लैम्ब्डा एक्सप्रेशन के बारे में कोई जानकारी नहीं है। या हो सकता है कि उन्होंने लैम्ब्डा भावों के बारे में कुछ सुना हो, लेकिन विवरण की कमी है
  • यह उन लोगों के लिए है जिन्हें लैम्ब्डा अभिव्यक्तियों की एक निश्चित समझ है, लेकिन वे अभी भी उनके द्वारा भयभीत हैं और उनका उपयोग करने के लिए अभ्यस्त नहीं हैं।
जावा में लैम्ब्डा एक्सप्रेशन की व्याख्या।  उदाहरणों और कार्यों के साथ।  भाग 1 - 1यदि आप इनमें से किसी एक श्रेणी में फिट नहीं बैठते हैं, तो आपको यह लेख उबाऊ, त्रुटिपूर्ण, या आम तौर पर आपकी चाय का प्याला नहीं लग सकता है। इस मामले में, अन्य चीजों पर जाने के लिए स्वतंत्र महसूस करें या, यदि आप इस विषय में अच्छी तरह से वाकिफ हैं, तो कृपया टिप्पणियों में सुझाव दें कि मैं लेख को कैसे सुधार या पूरक कर सकता हूं। सामग्री किसी भी अकादमिक मूल्य का दावा नहीं करती है, अकेले नवीनता दें। इसके विपरीत: मैं उन चीजों का वर्णन करने की कोशिश करूंगा जो जटिल हैं (कुछ लोगों के लिए) यथासंभव सरलता से। स्ट्रीम एपीआई की व्याख्या करने के अनुरोध ने मुझे इसे लिखने के लिए प्रेरित किया। मैंने इसके बारे में सोचा और फैसला किया कि लैम्ब्डा एक्सप्रेशन को समझे बिना मेरे कुछ स्ट्रीम उदाहरण समझ से बाहर होंगे। तो हम लैम्ब्डा एक्सप्रेशंस के साथ शुरुआत करेंगे। इस लेख को समझने के लिए आपको क्या जानने की आवश्यकता है?
  1. आपको वस्तु-उन्मुख प्रोग्रामिंग (OOP) को समझना चाहिए, अर्थात्:

    • कक्षाएं, वस्तुएं और उनके बीच का अंतर;
    • इंटरफेस, वे कक्षाओं से कैसे भिन्न हैं, और इंटरफेस और कक्षाओं के बीच संबंध;
    • विधियाँ, उन्हें कैसे कॉल करें, अमूर्त विधियाँ (अर्थात कार्यान्वयन के बिना विधियाँ), विधि पैरामीटर, विधि तर्क और उन्हें कैसे पारित किया जाए;
    • पहुँच संशोधक, स्थिर विधियाँ/चर, अंतिम विधियाँ/चर;
    • कक्षाओं और इंटरफेस की विरासत, इंटरफेस की एकाधिक विरासत।
  2. जावा कोर का ज्ञान: सामान्य प्रकार (जेनेरिक), संग्रह (सूचियाँ), धागे।
खैर, चलिए इस पर आते हैं।

थोड़ा इतिहास

लैंबडा एक्सप्रेशंस कार्यात्मक प्रोग्रामिंग से जावा में आए, और वहां गणित से। संयुक्त राज्य अमेरिका में 20वीं शताब्दी के मध्य में, अलोंजो चर्च, जो गणित और सभी प्रकार के अमूर्तों के बहुत शौकीन थे, ने प्रिंसटन विश्वविद्यालय में काम किया। यह अलोंजो चर्च था जिसने लैम्ब्डा कैलकुलस का आविष्कार किया था, जो शुरू में अमूर्त विचारों का एक सेट था जो पूरी तरह से प्रोग्रामिंग से संबंधित नहीं था। एलन ट्यूरिंग और जॉन वॉन न्यूमैन जैसे गणितज्ञों ने उसी समय प्रिंसटन विश्वविद्यालय में काम किया। सब कुछ एक साथ आया: चर्च लैम्ब्डा कैलकुस के साथ आया। ट्यूरिंग ने अपनी अमूर्त कंप्यूटिंग मशीन विकसित की, जिसे अब "ट्यूरिंग मशीन" के रूप में जाना जाता है। और वॉन न्यूमैन ने एक कंप्यूटर आर्किटेक्चर का प्रस्ताव रखा जिसने आधुनिक कंप्यूटरों का आधार बनाया (जिसे अब "वॉन न्यूमैन आर्किटेक्चर" कहा जाता है)। उस समय अलोंजो चर्च' के विचार उनके सहयोगियों के कार्यों के रूप में इतने प्रसिद्ध नहीं हुए (शुद्ध गणित के क्षेत्र को छोड़कर)। हालांकि, थोड़ी देर बाद जॉन मैककार्थी (प्रिंसटन विश्वविद्यालय के स्नातक और, हमारी कहानी के समय, मैसाचुसेट्स इंस्टीट्यूट ऑफ टेक्नोलॉजी के एक कर्मचारी) चर्च के विचारों में रुचि रखते थे। 1958 में, उन्होंने उन विचारों के आधार पर पहली कार्यात्मक प्रोग्रामिंग भाषा, LISP बनाई। और 58 साल बाद, कार्यात्मक प्रोग्रामिंग के विचार जावा 8 में लीक हो गए। यहां तक ​​कि 70 साल भी नहीं बीते हैं... ईमानदारी से, यह एक गणितीय विचार को व्यवहार में लागू करने के लिए लिया गया सबसे लंबा समय नहीं है। मैसाचुसेट्स इंस्टीट्यूट ऑफ टेक्नोलॉजी का एक कर्मचारी) चर्च के विचारों में दिलचस्पी लेने लगा। 1958 में, उन्होंने उन विचारों के आधार पर पहली कार्यात्मक प्रोग्रामिंग भाषा, LISP बनाई। और 58 साल बाद, कार्यात्मक प्रोग्रामिंग के विचार जावा 8 में लीक हो गए। यहां तक ​​कि 70 साल भी नहीं बीते हैं... ईमानदारी से, यह एक गणितीय विचार को व्यवहार में लागू करने के लिए लिया गया सबसे लंबा समय नहीं है। मैसाचुसेट्स इंस्टीट्यूट ऑफ टेक्नोलॉजी का एक कर्मचारी) चर्च के विचारों में दिलचस्पी लेने लगा। 1958 में, उन्होंने उन विचारों के आधार पर पहली कार्यात्मक प्रोग्रामिंग भाषा, LISP बनाई। और 58 साल बाद, कार्यात्मक प्रोग्रामिंग के विचार जावा 8 में लीक हो गए। यहां तक ​​कि 70 साल भी नहीं बीते हैं... ईमानदारी से, यह एक गणितीय विचार को व्यवहार में लागू करने के लिए लिया गया सबसे लंबा समय नहीं है।

इस मामले का दिल

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

public void mySuperSort() { 
    // We do something here 
    if(compare(obj1, obj2) > 0) 
    // And then we do something here 
}
बयान में if, हम compare()तुलना करने के लिए दो वस्तुओं में गुजरने वाली विधि कहते हैं, और हम जानना चाहते हैं कि इनमें से कौन सी वस्तु "बड़ी" है। हम मानते हैं कि "बड़ा" "कम" से पहले आता है। मैंने उद्धरणों में "अधिक" रखा है, क्योंकि हम एक सार्वभौमिक विधि लिख रहे हैं जो न केवल आरोही क्रम में क्रमबद्ध करना जानता है, बल्कि अवरोही क्रम में भी (इस मामले में, "अधिक" वस्तु वास्तव में "कम" वस्तु होगी , और इसके विपरीत)। हमारे प्रकार के लिए विशिष्ट एल्गोरिथ्म सेट करने के लिए, हमें इसे अपने mySuperSort()तरीके से पास करने के लिए कुछ तंत्र की आवश्यकता होती है। इस तरह हम कॉल करने पर हमारी विधि को "नियंत्रित" करने में सक्षम होंगे। बेशक, हम दो अलग-अलग तरीके लिख सकते हैं - mySuperSortAscend()औरmySuperSortDescend()- आरोही और अवरोही क्रम में छाँटने के लिए। या हम विधि के लिए कुछ तर्क पारित कर सकते हैं (उदाहरण के लिए, एक बूलियन चर; यदि सत्य है, तो आरोही क्रम में क्रमबद्ध करें, और यदि असत्य है, तो अवरोही क्रम में)। लेकिन क्या होगा अगर हम कुछ जटिल चीजों को छाँटना चाहते हैं जैसे कि स्ट्रिंग सरणियों की सूची? हमारी mySuperSort()विधि कैसे जानेगी कि इन स्ट्रिंग सरणियों को कैसे क्रमबद्ध किया जाए? आकार से? सभी शब्दों की संचयी लंबाई से? शायद वर्णानुक्रम में सरणी में पहली स्ट्रिंग के आधार पर? और क्या होगा यदि हमें कुछ मामलों में सरणी आकार द्वारा सरणियों की सूची को क्रमबद्ध करने की आवश्यकता है, और अन्य मामलों में प्रत्येक सरणी में सभी शब्दों की संचयी लंबाई से? मुझे उम्मीद है कि आप पहले से ही तुलनित्रों के बारे में सुन चुके हैं और इस मामले में हम बस अपनी छँटाई विधि को एक तुलनित्र वस्तु पास करेंगे जो वांछित छँटाई एल्गोरिथ्म का वर्णन करता है। क्योंकि मानकsort()पद्धति को उसी सिद्धांत के आधार पर कार्यान्वित किया जाता है mySuperSort(), जिसका मैं sort()अपने उदाहरणों में उपयोग करूंगा।

String[] array1 = {"Dota", "GTA5", "Halo"}; 
String[] array2 = {"I", "really", "love", "Java"}; 
String[] array3 = {"if", "then", "else"}; 

List<String[]> arrays = new ArrayList<>(); 
arrays.add(array1); 
arrays.add(array2); 
arrays.add(array3); 

Comparator<;String[]> sortByLength = new Comparator<String[]>() { 
    @Override 
    public int compare(String[] o1, String[] o2) { 
        return o1.length - o2.length; 
    } 
}; 

Comparator<String[]> sortByCumulativeWordLength = new Comparator<String[]>() { 

    @Override 
    public int compare(String[] o1, String[] o2) { 
        int length1 = 0; 
        int length2 = 0; 
        for (String s : o1) { 
            length1 += s.length(); 
        } 

        for (String s : o2) { 
            length2 += s.length(); 
        } 

        return length1 - length2; 
    } 
};

arrays.sort(sortByLength);
परिणाम:

  1. Dota GTA5 Halo
  2. if then else
  3. I really love Java
यहाँ सरणियों को प्रत्येक सरणी में शब्दों की संख्या के अनुसार क्रमबद्ध किया गया है। कम शब्दों वाली एक सरणी को "कम" माना जाता है। इसलिए यह सबसे पहले आता है। अधिक शब्दों वाली एक सरणी को "बड़ा" माना जाता है और अंत में रखा जाता है। यदि हम sort()विधि के लिए एक अलग तुलनित्र पास करते हैं, जैसे sortByCumulativeWordLength, तो हमें एक अलग परिणाम मिलेगा:

  1. if then else
  2. Dota GTA5 Halo
  3. I really love Java
अब हैं सरणियों को सरणी के शब्दों में अक्षरों की कुल संख्या द्वारा क्रमबद्ध किया जाता है। पहली सरणी में, 10 अक्षर हैं, दूसरे में - 12, और तीसरे में - 15। यदि हमारे पास केवल एक तुलनित्र है, तो हमें इसके लिए एक अलग चर घोषित करने की आवश्यकता नहीं है। sort()इसके बजाय, हम विधि को कॉल करने के समय ही एक अनाम वर्ग बना सकते हैं। कुछ इस तरह:

String[] array1 = {"Dota", "GTA5", "Halo"}; 
String[] array2 = {"I", "really", "love", "Java"}; 
String[] array3 = {"if", "then", "else"}; 

List<String[]> arrays = new ArrayList<>(); 

arrays.add(array1); 
arrays.add(array2); 
arrays.add(array3); 

arrays.sort(new Comparator<String[]>() { 
    @Override 
    public int compare(String[] o1, String[] o2) { 
        return o1.length - o2.length; 
    } 
}); 
हम पहले मामले की तरह ही परिणाम प्राप्त करेंगे। कार्य 1। इस उदाहरण को फिर से लिखें ताकि यह प्रत्येक सरणी में शब्दों की संख्या के आरोही क्रम में नहीं, बल्कि अवरोही क्रम में सरणियों को क्रमबद्ध करे। हम यह सब पहले से ही जानते हैं। हम जानते हैं कि वस्तुओं को विधियों में कैसे पारित किया जाए। इस समय हमें जो चाहिए उसके आधार पर, हम अलग-अलग वस्तुओं को एक विधि में पास कर सकते हैं, जो तब हमारे द्वारा लागू की गई विधि को लागू करेगा। यह सवाल पूछता है: दुनिया में हमें यहां लैम्ब्डा अभिव्यक्ति की आवश्यकता क्यों है?  क्योंकि लैम्ब्डा एक्सप्रेशन एक ऐसी वस्तु है जिसमें बिल्कुल एक विधि होती है। एक "विधि वस्तु" की तरह। किसी वस्तु में पैक की गई विधि। इसमें थोड़ा अपरिचित सिंटैक्स है (लेकिन बाद में उस पर और अधिक)। आइए इस कोड पर एक और नजर डालते हैं:

arrays.sort(new Comparator<String[]>() { 
    @Override 
    public int compare(String[] o1, String[] o2) { 
        return o1.length - o2.length; 
    } 
});
यहां हम अपनी सरणी सूची लेते हैं और इसकी sort()विधि को कॉल करते हैं, जिसमें हम एक तुलनित्र वस्तु को एक compare()विधि के साथ पास करते हैं (इसका नाम हमारे लिए कोई मायने नहीं रखता है - आखिरकार, यह इस वस्तु की एकमात्र विधि है, इसलिए हम गलत नहीं हो सकते)। इस पद्धति के दो पैरामीटर हैं जिनके साथ हम काम करेंगे। यदि आप IntelliJ IDEA में काम कर रहे हैं, तो आपने देखा होगा कि यह कोड को महत्वपूर्ण रूप से संक्षिप्त करने की पेशकश करता है:

arrays.sort((o1, o2) -> o1.length - o2.length);
यह छह पंक्तियों को घटाकर एक छोटा कर देता है। 6 पंक्तियों को एक छोटी पंक्ति के रूप में फिर से लिखा गया है। कुछ गायब हो गया, लेकिन मैं गारंटी देता हूं कि यह कुछ महत्वपूर्ण नहीं था। यह कोड ठीक उसी तरह काम करेगा जैसे यह एक अनाम वर्ग के साथ होता है। टास्क 2. लैम्ब्डा एक्सप्रेशन का उपयोग करके टास्क 1 के समाधान को फिर से लिखने का अनुमान लगाएं (कम से कम, IntelliJ IDEA से अपने अनाम वर्ग को लैम्ब्डा एक्सप्रेशन में बदलने के लिए कहें)।

आइए इंटरफेस के बारे में बात करते हैं

सिद्धांत रूप में, एक इंटरफ़ेस केवल सार विधियों की एक सूची है। जब हम एक ऐसा वर्ग बनाते हैं जो कुछ इंटरफ़ेस को लागू करता है, तो हमारी कक्षा को इंटरफ़ेस में शामिल विधियों को लागू करना चाहिए (या हमें कक्षा को सार बनाना होगा)। कई अलग-अलग तरीकों के साथ इंटरफेस हैं (उदाहरण के लिए,  List), और केवल एक विधि के साथ इंटरफेस हैं (उदाहरण के लिए, Comparatorया Runnable)। ऐसे इंटरफेस हैं जिनमें एक भी तरीका नहीं है (तथाकथित मार्कर इंटरफेस जैसे Serializable)। जिन इंटरफेस में केवल एक विधि होती है उन्हें कार्यात्मक इंटरफेस भी कहा जाता है । जावा 8 में, उन्हें एक विशेष एनोटेशन के साथ भी चिह्नित किया गया है:@FunctionalInterface. ये एकल-विधि इंटरफेस हैं जो लैम्ब्डा एक्सप्रेशन के लिए लक्ष्य प्रकार के रूप में उपयुक्त हैं। जैसा कि मैंने ऊपर कहा, एक लैम्ब्डा अभिव्यक्ति एक वस्तु में लिपटी हुई विधि है। और जब हम इस तरह की वस्तु को पास करते हैं, तो हम अनिवार्य रूप से इस एकल विधि को पास कर रहे होते हैं। यह पता चला है कि हमें परवाह नहीं है कि विधि क्या कहलाती है। केवल चीजें जो हमारे लिए मायने रखती हैं वे हैं विधि पैरामीटर और निश्चित रूप से विधि का शरीर। संक्षेप में, एक लैम्ब्डा अभिव्यक्ति एक कार्यात्मक इंटरफ़ेस का कार्यान्वयन है। जहाँ भी हम एक एकल विधि के साथ एक इंटरफ़ेस देखते हैं, एक अनाम वर्ग को लैम्ब्डा के रूप में फिर से लिखा जा सकता है। यदि इंटरफ़ेस में एक से अधिक या कम विधियाँ हैं, तो एक लैम्ब्डा अभिव्यक्ति काम नहीं करेगी और हम इसके बजाय एक अनाम वर्ग या एक साधारण वर्ग के उदाहरण का उपयोग करेंगे। अब लैम्ब्डा में थोड़ा खोदने का समय है। :)

वाक्य - विन्यास

सामान्य वाक्य रचना कुछ इस प्रकार है:

(parameters) -> {method body}
यही है, विधि पैरामीटर के आस-पास कोष्ठक, एक "तीर" (एक हाइफ़न और अधिक से अधिक चिह्न द्वारा गठित), और फिर हमेशा की तरह ब्रेसिज़ में विधि निकाय। पैरामीटर इंटरफ़ेस विधि में निर्दिष्ट के अनुरूप हैं। यदि चर प्रकार स्पष्ट रूप से संकलक द्वारा निर्धारित किए जा सकते हैं (हमारे मामले में, यह जानता है कि हम स्ट्रिंग सरणियों के साथ काम कर रहे हैं, क्योंकि हमारी Listवस्तु का उपयोग करके टाइप किया गया है String[]), तो आपको उनके प्रकारों को इंगित करने की आवश्यकता नहीं है।
यदि वे अस्पष्ट हैं, तो प्रकार इंगित करें। अगर जरूरत नहीं है तो आईडिया इसे ग्रे रंग में रंग देगा।
आप इस Oracle ट्यूटोरियल और अन्य जगहों पर अधिक पढ़ सकते हैं । इसे " लक्ष्य टाइपिंग " कहा जाता है। आप जो चाहें वेरिएबल्स को नाम दे सकते हैं - आपको इंटरफ़ेस में निर्दिष्ट समान नामों का उपयोग करने की आवश्यकता नहीं है। यदि कोई पैरामीटर नहीं हैं, तो केवल खाली कोष्ठक इंगित करें। यदि केवल एक पैरामीटर है, तो बिना किसी कोष्ठक के केवल चर नाम इंगित करें। अब जब हम मापदंडों को समझते हैं, तो यह लैम्ब्डा अभिव्यक्ति के शरीर पर चर्चा करने का समय है। कर्ली ब्रेसिज़ के अंदर, आप कोड वैसे ही लिखते हैं जैसे आप एक सामान्य विधि के लिए लिखते हैं। यदि आपके कोड में एक पंक्ति है, तो आप कर्ली ब्रेसिज़ को पूरी तरह से छोड़ सकते हैं (if-statement और for-loops के समान)। यदि आपका सिंगल-लाइन लैम्ब्डा कुछ लौटाता है, तो आपको इसमें शामिल करने की आवश्यकता नहीं हैreturnकथन। लेकिन यदि आप घुंघराले ब्रेसिज़ का उपयोग करते हैं, तो आपको स्पष्ट रूप से एक returnकथन शामिल करना होगा, जैसा कि आप एक सामान्य विधि में करेंगे।

उदाहरण

उदाहरण 1।

() -> {}
सबसे सरल उदाहरण। और सबसे व्यर्थ :), क्योंकि यह कुछ भी नहीं करता है। उदाहरण 2।

() -> ""
एक और दिलचस्प उदाहरण। यह कुछ भी नहीं लेता है और एक खाली स्ट्रिंग देता है ( returnछोड़ा गया है, क्योंकि यह अनावश्यक है)। यहाँ वही बात है, लेकिन इसके साथ return:

() -> { 
    return ""; 
}
उदाहरण 3. "हैलो, वर्ल्ड!" लैम्ब्डा का उपयोग करना

() -> System.out.println("Hello, World!")
returnयह कुछ भी नहीं लेता है और कुछ भी वापस नहीं करता है (हम कॉल से पहले नहीं रख सकते हैं System.out.println(), क्योंकि println()विधि का रिटर्न प्रकार है void)। यह केवल अभिवादन प्रदर्शित करता है। यह इंटरफ़ेस के कार्यान्वयन के लिए आदर्श है Runnable। निम्नलिखित उदाहरण अधिक पूर्ण है:

public class Main { 
    public static void main(String[] args) { 
        new Thread(() -> System.out.println("Hello, World!")).start(); 
    } 
}
या इस तरह:

public class Main { 
    public static void main(String[] args) { 
        Thread t = new Thread(() -> System.out.println("Hello, World!")); 
        t.start();
    } 
}
या हम लैम्ब्डा अभिव्यक्ति को Runnableऑब्जेक्ट के रूप में भी सहेज सकते हैं और फिर इसे Threadकन्स्ट्रक्टर को पास कर सकते हैं:

public class Main { 
    public static void main(String[] args) { 
        Runnable runnable = () -> System.out.println("Hello, World!"); 
        Thread t = new Thread(runnable); 
        t.start(); 
    } 
}
आइए उस क्षण पर करीब से नज़र डालें जब लैम्ब्डा एक्सप्रेशन को वेरिएबल में सेव किया जाता है। इंटरफ़ेस Runnableहमें बताता है कि इसकी वस्तुओं में एक public void run()विधि होनी चाहिए। इंटरफ़ेस के अनुसार, runविधि कोई पैरामीटर नहीं लेती है। और यह कुछ भी नहीं देता है, यानी इसका रिटर्न प्रकार है void। तदनुसार, यह कोड एक ऐसी विधि के साथ एक वस्तु बनाएगा जो कुछ भी नहीं लेती या वापस नहीं करती है। यह Runnableइंटरफ़ेस की run()विधि से पूरी तरह मेल खाता है। इसलिए हम इस लैम्ब्डा अभिव्यक्ति को एक Runnableचर में रखने में सक्षम थे।  उदाहरण 4।

() -> 42
दोबारा, यह कुछ भी नहीं लेता है, लेकिन यह संख्या 42 देता है। इस तरह की लैम्ब्डा अभिव्यक्ति को एक चर में रखा जा सकता है Callable, क्योंकि इस इंटरफ़ेस में केवल एक ही तरीका है जो कुछ ऐसा दिखता है:

V call(),
V वापसी प्रकार  कहां  है (हमारे मामले में, int)। तदनुसार, हम लैम्ब्डा अभिव्यक्ति को निम्नानुसार सहेज सकते हैं:

Callable<Integer> c = () -> 42;
उदाहरण 5. एक लैम्ब्डा अभिव्यक्ति जिसमें कई पंक्तियाँ शामिल हैं

() -> { 
    String[] helloWorld = {"Hello", "World!"}; 
    System.out.println(helloWorld[0]); 
    System.out.println(helloWorld[1]); 
}
दोबारा, यह एक लैम्ब्डा अभिव्यक्ति है जिसमें कोई पैरामीटर नहीं है और voidवापसी प्रकार है (क्योंकि कोई returnबयान नहीं है)।  उदाहरण 6

x -> x
यहां हम एक xचर लेते हैं और इसे वापस कर देते हैं। कृपया ध्यान दें कि यदि केवल एक पैरामीटर है, तो आप उसके चारों ओर कोष्ठक छोड़ सकते हैं। यहाँ वही बात है, लेकिन कोष्ठक के साथ:

(x) -> x
और यहाँ एक स्पष्ट रिटर्न स्टेटमेंट के साथ एक उदाहरण दिया गया है:

x -> { 
    return x;
}
या इस तरह कोष्ठक और रिटर्न स्टेटमेंट के साथ:

(x) -> { 
    return x;
}
या प्रकार के स्पष्ट संकेत के साथ (और इस प्रकार कोष्ठक के साथ):

(int x) -> x
उदाहरण 7

x -> ++x
हम xइसे लेते हैं और वापस करते हैं, लेकिन केवल 1 जोड़ने के बाद। आप लैम्ब्डा को इस तरह फिर से लिख सकते हैं:

x -> x + 1
दोनों ही मामलों में, हम स्टेटमेंट के साथ-साथ पैरामीटर और मेथड बॉडी के आसपास के कोष्ठकों को छोड़ देते हैं return, क्योंकि वे वैकल्पिक हैं। उदाहरण 6 में कोष्ठकों और रिटर्न स्टेटमेंट वाले संस्करण दिए गए हैं। उदाहरण 8

(x, y) -> x % y
हम द्वारा के विभाजन का शेष भाग लेते हैं और लौटाते xहैं । मापदंडों के आसपास कोष्ठक यहाँ आवश्यक हैं। वे केवल तभी वैकल्पिक होते हैं जब केवल एक पैरामीटर होता है। यहाँ यह प्रकारों के स्पष्ट संकेत के साथ है: yxy

(double x, int y) -> x % y
उदाहरण 9

(Cat cat, String name, int age) -> {
    cat.setName(name); 
    cat.setAge(age); 
}
हम एक Catवस्तु, एक Stringनाम और एक अंतर आयु लेते हैं। विधि में ही, हम बिल्ली पर चर सेट करने के लिए पारित नाम और आयु का उपयोग करते हैं। क्योंकि हमारी catवस्तु एक संदर्भ प्रकार है, इसे लैम्ब्डा एक्सप्रेशन के बाहर बदल दिया जाएगा (इसे पारित नाम और आयु मिल जाएगी)। यहां थोड़ा और जटिल संस्करण है जो एक समान लैम्ब्डा का उपयोग करता है:

public class Main { 

    public static void main(String[] args) { 
        // Create a cat and display it to confirm that it is "empty" 
        Cat myCat = new Cat(); 
        System.out.println(myCat);
 
        // Create a lambda 
        Settable<Cat> s = (obj, name, age) -> { 
            obj.setName(name); 
            obj.setAge(age); 

        }; 

        // Call a method to which we pass the cat and lambda 
        changeEntity(myCat, s); 

        // Display the cat on the screen and see that its state has changed (it has a name and age) 
        System.out.println(myCat); 

    } 

    private static <T extends HasNameAndAge>  void changeEntity(T entity, Settable<T> s) { 
        s.set(entity, "Smokey", 3); 
    }
}

interface HasNameAndAge { 
    void setName(String name); 
    void setAge(int age); 
}

interface Settable<C extends HasNameAndAge> { 
    void set(C entity, String name, int age); 
}

class Cat implements HasNameAndAge { 
    private String name; 
    private int age; 

    @Override 
    public void setName(String name) { 
        this.name = name;
    }

    @Override
    public void setAge(int age) {
        this.age = age; 
    } 

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' + 
                ", age=" + age + 
                '}';
    }
}
परिणाम:

Cat{name='null', age=0}
Cat{name='Smokey', age=3}
जैसा कि आप देख सकते हैं, Catवस्तु में एक राज्य था, और फिर लैम्ब्डा अभिव्यक्ति का उपयोग करने के बाद राज्य बदल गया। लैम्ब्डा एक्सप्रेशंस जेनरिक के साथ पूरी तरह से मेल खाते हैं। Dogऔर अगर हमें एक ऐसा वर्ग बनाने की आवश्यकता है जो लागू भी हो, तो हम  लैम्ब्डा अभिव्यक्ति को बदले बिना विधि में HasNameAndAgeसमान संचालन कर सकते हैं । कार्य 3। एक विधि के साथ एक कार्यात्मक इंटरफ़ेस लिखें जो एक संख्या लेता है और एक बूलियन मान देता है। एक लैम्ब्डा अभिव्यक्ति के रूप में इस तरह के एक इंटरफ़ेस के कार्यान्वयन को लिखें जो कि पारित संख्या 13 से विभाज्य होने पर सही हो जाती है। कार्य 4।Dogmain()एक विधि के साथ एक कार्यात्मक इंटरफ़ेस लिखें जो दो तार लेता है और एक स्ट्रिंग भी देता है। लैम्ब्डा अभिव्यक्ति के रूप में ऐसे इंटरफ़ेस का कार्यान्वयन लिखें जो लंबी स्ट्रिंग लौटाता है। कार्य 5। एक विधि के साथ एक कार्यात्मक इंटरफ़ेस लिखें जो तीन फ़्लोटिंग-पॉइंट नंबर लेता है: ए, बी, और सी और फ़्लोटिंग-पॉइंट नंबर भी देता है। एक लैम्ब्डा अभिव्यक्ति के रूप में इस तरह के एक इंटरफ़ेस का कार्यान्वयन लिखें जो विवेचक को लौटाता है। यदि आप भूल गए हैं, तो वह है D = b^2 — 4acकार्य 6। कार्य 5 से कार्यात्मक इंटरफ़ेस का उपयोग करते हुए, एक लैम्ब्डा अभिव्यक्ति लिखें जो परिणाम देता है a * b^cजावा में लैम्ब्डा एक्सप्रेशन की व्याख्या। उदाहरणों और कार्यों के साथ। भाग 2
टिप्पणियां
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION