CodeGym /Java Blog /यादृच्छिक /जावा मधील लॅम्बडा अभिव्यक्तींचे स्पष्टीकरण. उदाहरणे आणि क...
John Squirrels
पातळी 41
San Francisco

जावा मधील लॅम्बडा अभिव्यक्तींचे स्पष्टीकरण. उदाहरणे आणि कार्यांसह. भाग 1

यादृच्छिक या ग्रुपमध्ये प्रकाशित केले
हा लेख कोणासाठी आहे?
  • हे अशा लोकांसाठी आहे ज्यांना वाटते की त्यांना जावा कोअर आधीच चांगले माहित आहे, परंतु त्यांना जावामधील लॅम्बडा अभिव्यक्तीबद्दल काहीच माहिती नाही. किंवा कदाचित त्यांनी लॅम्बडा अभिव्यक्तींबद्दल काहीतरी ऐकले असेल, परंतु तपशीलांची कमतरता आहे
  • हे अशा लोकांसाठी आहे ज्यांना लॅम्बडा अभिव्यक्तींची विशिष्ट समज आहे, परंतु तरीही ते घाबरलेले आहेत आणि ते वापरण्याची सवय नाही.
जावा मधील लॅम्बडा अभिव्यक्तींचे स्पष्टीकरण.  उदाहरणे आणि कार्यांसह.  भाग १ - १जर तुम्ही यापैकी एका वर्गवारीत बसत नसाल, तर तुम्हाला हा लेख कंटाळवाणा, सदोष किंवा सामान्यतः तुमचा चहाचा कप वाटू शकत नाही. या प्रकरणात, इतर गोष्टींकडे जाण्यास मोकळ्या मनाने किंवा, जर तुम्हाला या विषयात पारंगत असेल, तर कृपया मी लेखात सुधारणा किंवा पूरक कसे बनवू शकेन याबद्दल टिप्पण्यांमध्ये सूचना द्या. साहित्यात कोणतेही शैक्षणिक मूल्य असल्याचा दावा करत नाही, नवीनता सोडा. अगदी उलट: मी शक्य तितक्या क्लिष्ट (काही लोकांसाठी) गोष्टींचे वर्णन करण्याचा प्रयत्न करेन. स्ट्रीम API स्पष्ट करण्याच्या विनंतीने मला हे लिहिण्यास प्रेरित केले. मी त्याबद्दल विचार केला आणि ठरवले की माझ्या प्रवाहातील काही उदाहरणे लॅम्बडा अभिव्यक्ती समजून घेतल्याशिवाय अनाकलनीय असतील. तर आपण lambda expressions सह सुरुवात करू. हा लेख समजून घेण्यासाठी तुम्हाला काय माहित असणे आवश्यक आहे?
  1. तुम्हाला ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग (OOP) समजले पाहिजे, म्हणजे:

    • वर्ग, वस्तू आणि त्यांच्यातील फरक;
    • इंटरफेस, ते वर्गांपेक्षा कसे वेगळे आहेत आणि इंटरफेस आणि वर्गांमधील संबंध;
    • पद्धती, त्यांना कसे कॉल करायचे, अमूर्त पद्धती (म्हणजे अंमलबजावणी नसलेल्या पद्धती), पद्धतीचे मापदंड, पद्धतीचे युक्तिवाद आणि ते कसे पास करायचे;
    • ऍक्सेस मॉडिफायर्स, स्टॅटिक पद्धती/व्हेरिएबल्स, अंतिम पद्धती/व्हेरिएबल्स;
    • वर्ग आणि इंटरफेसचा वारसा, इंटरफेसचा एकाधिक वारसा.
  2. जावा कोरचे ज्ञान: जेनेरिक प्रकार (जेनेरिक), संग्रह (याद्या), धागे.
बरं, चला ते मिळवूया.

थोडा इतिहास

लॅम्बडा एक्स्प्रेशन्स फंक्शनल प्रोग्रामिंगमधून जावामध्ये आले आणि तेथून गणितातून आले. 20 व्या शतकाच्या मध्यात युनायटेड स्टेट्समध्ये, अलोन्झो चर्च, ज्यांना गणित आणि सर्व प्रकारच्या अमूर्त गोष्टींची खूप आवड होती, त्यांनी प्रिन्स्टन विद्यापीठात काम केले. अलोन्झो चर्चने लॅम्बडा कॅल्क्युलसचा शोध लावला, जो सुरुवातीला अमूर्त कल्पनांचा संच होता जो प्रोग्रामिंगशी पूर्णपणे संबंधित नव्हता. अॅलन ट्युरिंग आणि जॉन फॉन न्यूमन या गणितज्ञांनी एकाच वेळी प्रिन्स्टन विद्यापीठात काम केले. सर्व काही एकत्र आले: चर्च लॅम्बडा कॅल्क्युलससह आले. ट्युरिंगने त्याचे अमूर्त संगणन यंत्र विकसित केले, जे आता "ट्युरिंग मशीन" म्हणून ओळखले जाते. आणि वॉन न्यूमनने एक संगणक आर्किटेक्चर प्रस्तावित केले ज्याने आधुनिक संगणकांचा आधार बनवला (आता त्याला "व्हॉन न्यूमन आर्किटेक्चर" म्हटले जाते). त्या वेळी, अलोन्झो चर्च' च्या कल्पना त्याच्या सहकाऱ्यांच्या कृतींइतक्या प्रसिद्ध झाल्या नाहीत (शुद्ध गणिताच्या क्षेत्राचा अपवाद वगळता). तथापि, थोड्या वेळाने जॉन मॅककार्थी (प्रिन्सटन युनिव्हर्सिटीचे पदवीधर आणि आमच्या कथेच्या वेळी, मॅसॅच्युसेट्स इन्स्टिट्यूट ऑफ टेक्नॉलॉजीचे कर्मचारी) यांना चर्चच्या कल्पनांमध्ये रस निर्माण झाला. 1958 मध्ये, त्यांनी त्या कल्पनांवर आधारित LISP ही पहिली कार्यात्मक प्रोग्रामिंग भाषा तयार केली. आणि 58 वर्षांनंतर, Java 8 मध्ये फंक्शनल प्रोग्रामिंगच्या कल्पना लीक झाल्या. 70 वर्षेही उलटली नाहीत... प्रामाणिकपणे, गणितीय कल्पना व्यवहारात लागू करण्यासाठी ही सर्वात जास्त वेळ नाही. मॅसॅच्युसेट्स इन्स्टिट्यूट ऑफ टेक्नॉलॉजीच्या कर्मचाऱ्याला चर्चच्या कल्पनांमध्ये रस होता. 1958 मध्ये, त्यांनी त्या कल्पनांवर आधारित LISP ही पहिली कार्यात्मक प्रोग्रामिंग भाषा तयार केली. आणि 58 वर्षांनंतर, Java 8 मध्ये फंक्शनल प्रोग्रामिंगच्या कल्पना लीक झाल्या. 70 वर्षेही उलटली नाहीत... प्रामाणिकपणे, गणितीय कल्पना व्यवहारात लागू करण्यासाठी ही सर्वात जास्त वेळ नाही. मॅसॅच्युसेट्स इन्स्टिट्यूट ऑफ टेक्नॉलॉजीच्या कर्मचाऱ्याला चर्चच्या कल्पनांमध्ये रस होता. 1958 मध्ये, त्यांनी त्या कल्पनांवर आधारित LISP ही पहिली कार्यात्मक प्रोग्रामिंग भाषा तयार केली. आणि 58 वर्षांनंतर, Java 8 मध्ये फंक्शनल प्रोग्रामिंगच्या कल्पना लीक झाल्या. 70 वर्षेही उलटली नाहीत... प्रामाणिकपणे, गणितीय कल्पना व्यवहारात लागू करण्यासाठी ही सर्वात जास्त वेळ नाही.

प्रकरणाचे हृदय

लॅम्बडा अभिव्यक्ती हे एक प्रकारचे कार्य आहे. तुम्ही ही एक सामान्य Java पद्धत मानू शकता परंतु युक्तिवाद म्हणून इतर पद्धतींमध्ये पास करण्याच्या विशिष्ट क्षमतेसह. ते बरोबर आहे. केवळ संख्या, स्ट्रिंग आणि मांजरीच नव्हे तर इतर पद्धती देखील पास करणे शक्य झाले आहे! आम्हाला याची कधी गरज पडू शकते? हे उपयुक्त ठरेल, उदाहरणार्थ, आम्हाला काही कॉलबॅक पद्धत पास करायची असल्यास. म्हणजेच, आपण ज्या पद्धतीला कॉल करतो त्या पद्धतीची आपल्याला आवश्यकता असल्यास आपण ज्या पद्धतीकडे जातो त्याला कॉल करण्याची क्षमता असते. दुसऱ्या शब्दांत, म्हणून आमच्याकडे विशिष्ट परिस्थितीत एक कॉलबॅक आणि इतरांमध्ये वेगळा कॉलबॅक पास करण्याची क्षमता आहे. आणि त्यामुळे आमची पद्धत जी आमचे कॉलबॅक प्राप्त करते त्यांना कॉल करते. वर्गीकरण हे एक साधे उदाहरण आहे. समजा आम्ही काही हुशार वर्गीकरण अल्गोरिदम लिहित आहोत जे असे दिसते:

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
आता are arrays ची क्रमवारी अॅरेच्या शब्दांमधील एकूण अक्षरांच्या संख्येनुसार केली जाते. पहिल्या अॅरेमध्ये 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 ला तुमचा अनामित वर्ग lambda अभिव्यक्तीमध्ये रूपांतरित करण्यास सांगा).

चला इंटरफेसबद्दल बोलूया

तत्वतः, इंटरफेस म्हणजे फक्त अमूर्त पद्धतींची यादी. जेव्हा आपण एखादा वर्ग तयार करतो जो काही इंटरफेस लागू करतो, तेव्हा आपल्या वर्गाने इंटरफेसमध्ये समाविष्ट केलेल्या पद्धती लागू केल्या पाहिजेत (किंवा आपल्याला वर्ग अमूर्त बनवावा लागेल). बर्‍याच वेगवेगळ्या पद्धतींसह इंटरफेस आहेत (उदाहरणार्थ,  List), आणि फक्त एकाच पद्धतीसह इंटरफेस आहेत (उदाहरणार्थ, Comparatorकिंवा Runnable). असे इंटरफेस आहेत ज्यात एकच पद्धत नाही (तथाकथित मार्कर इंटरफेस जसे की Serializable). ज्या इंटरफेसमध्ये फक्त एक पद्धत आहे त्यांना फंक्शनल इंटरफेस देखील म्हणतात . Java 8 मध्ये, त्यांना विशेष भाष्याने चिन्हांकित केले आहे:@FunctionalInterface. हे एकल-पद्धतीचे इंटरफेस आहेत जे लॅम्बडा अभिव्यक्तीसाठी लक्ष्य प्रकार म्हणून योग्य आहेत. मी वर म्हटल्याप्रमाणे, लॅम्बडा अभिव्यक्ती ही ऑब्जेक्टमध्ये गुंडाळलेली पद्धत आहे. आणि जेव्हा आपण अशी एखादी वस्तू पास करतो, तेव्हा आपण मूलत: ही एक पद्धत पास करत असतो. या पद्धतीला काय म्हणतात याची आम्हाला पर्वा नाही. आमच्यासाठी महत्त्वाच्या गोष्टी म्हणजे पद्धतीचे मापदंड आणि अर्थातच, पद्धतीचा मुख्य भाग. थोडक्यात, लॅम्बडा अभिव्यक्ती म्हणजे फंक्शनल इंटरफेसची अंमलबजावणी. जिथे जिथे आपल्याला एकाच पद्धतीचा इंटरफेस दिसतो तिथे एक अनामिक वर्ग lambda म्हणून पुन्हा लिहिला जाऊ शकतो. जर इंटरफेसमध्ये एकापेक्षा जास्त किंवा कमी पद्धती असतील, तर lambda अभिव्यक्ती कार्य करणार नाही आणि आम्ही त्याऐवजी निनावी वर्ग किंवा अगदी सामान्य वर्गाचे उदाहरण वापरू. आता लॅम्बडास मध्ये थोडे खोदण्याची वेळ आली आहे. :)

मांडणी

सामान्य वाक्यरचना असे काहीतरी आहे:

(parameters) -> {method body}
म्हणजेच, मेथड पॅरामीटर्सभोवती कंस, एक "बाण" (हायफन आणि त्याहून अधिक चिन्हाने तयार केलेला), आणि नंतर नेहमीप्रमाणे ब्रेसेसमध्ये मेथड बॉडी. पॅरामीटर्स इंटरफेस पद्धतीमध्ये निर्दिष्ट केलेल्यांशी संबंधित आहेत. जर व्हेरिएबलचे प्रकार कंपायलरद्वारे निःसंदिग्धपणे निर्धारित केले जाऊ शकतात (आमच्या बाबतीत, हे माहित आहे की आम्ही स्ट्रिंग अॅरेसह काम करत आहोत, कारण आमचा Listऑब्जेक्ट ] वापरून टाइप केला आहे String[), तर तुम्हाला त्यांचे प्रकार सूचित करण्याची गरज नाही.
जर ते अस्पष्ट असतील तर प्रकार सूचित करा. जर गरज नसेल तर IDEA त्यास राखाडी रंग देईल.
तुम्ही या ओरॅकल ट्यूटोरियलमध्ये आणि इतरत्र अधिक वाचू शकता . याला " लक्ष्य टायपिंग " म्हणतात. तुम्ही व्हेरिएबल्सना तुम्हाला हवे ते नाव देऊ शकता — तुम्हाला इंटरफेसमध्ये निर्दिष्ट केलेली समान नावे वापरण्याची गरज नाही. कोणतेही पॅरामीटर्स नसल्यास, फक्त रिक्त कंस सूचित करा. फक्त एक पॅरामीटर असल्यास, कोणत्याही कंस न करता फक्त व्हेरिएबलचे नाव सूचित करा. आता आम्हाला पॅरामीटर्स समजले आहेत, लॅम्बडा अभिव्यक्तीच्या मुख्य भागावर चर्चा करण्याची वेळ आली आहे. कुरळे ब्रेसेसच्या आत, तुम्ही सामान्य पद्धतीप्रमाणेच कोड लिहिता. जर तुमच्या कोडमध्ये एकाच ओळीचा समावेश असेल, तर तुम्ही कर्ली ब्रेसेस पूर्णपणे वगळू शकता (if-statements आणि for-loops प्रमाणे). तुमचा सिंगल-लाइन लॅम्बडा काही परत करत असल्यास, तुम्हाला ए समाविष्ट करण्याची गरज नाहीreturnविधान. परंतु जर तुम्ही कुरळे ब्रेसेस वापरत असाल, तर तुम्ही returnसामान्य पद्धतीप्रमाणे स्पष्टपणे विधान समाविष्ट केले पाहिजे.

उदाहरणे

उदाहरण १.

() -> {}
साधे उदाहरण. आणि सर्वात निरर्थक :), कारण ते काहीही करत नाही. उदाहरण २.

() -> ""
आणखी एक मनोरंजक उदाहरण. हे काहीही घेत नाही आणि रिक्त स्ट्रिंग परत करते ( returnवगळले आहे, कारण ते अनावश्यक आहे). येथे समान गोष्ट आहे, परंतु यासह return:

() -> { 
    return ""; 
}
उदाहरण 3. "हॅलो, वर्ल्ड!" lambdas वापरून

() -> 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.  उदाहरण ४.

() -> 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
उदाहरण ९

(Cat cat, String name, int age) -> {
    cat.setName(name); 
    cat.setAge(age); 
}
आपण एखादी Catवस्तू, Stringनाव आणि पूर्ण वय घेतो. पद्धतीमध्येच, आम्ही मांजरीवर व्हेरिएबल्स सेट करण्यासाठी उत्तीर्ण झालेले नाव आणि वय वापरतो. catआमचा ऑब्जेक्ट हा संदर्भ प्रकार असल्यामुळे , तो lambda अभिव्यक्तीच्या बाहेर बदलला जाईल (त्याला उत्तीर्ण झालेले नाव आणि वय मिळेल). येथे एक थोडी अधिक क्लिष्ट आवृत्ती आहे जी समान लॅम्बडा वापरते:

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ऑब्जेक्टची एक अवस्था होती आणि नंतर आम्ही lambda अभिव्यक्ती वापरल्यानंतर स्थिती बदलली. लॅम्बडा अभिव्यक्ती जेनेरिकसह उत्तम प्रकारे एकत्र होतात. Dogआणि जर आपल्याला सुद्धा लागू करणारा वर्ग तयार करायचा असेल , तर आपण  lambda अभिव्यक्ती न बदलता पद्धतीमध्ये समान HasNameAndAgeक्रिया करू शकतो . कार्य 3. एक कार्यात्मक इंटरफेस अशा पद्धतीसह लिहा जी संख्या घेते आणि बुलियन मूल्य परत करते. अशा इंटरफेसची अंमलबजावणी लॅम्बडा अभिव्यक्ती म्हणून लिहा जी उत्तीर्ण संख्या 13 ने भागल्यास सत्य मिळवते. कार्य 4.Dogmain()फंक्शनल इंटरफेस अशा पद्धतीसह लिहा जी दोन स्ट्रिंग घेते आणि एक स्ट्रिंग देखील देते. लॅम्बडा एक्सप्रेशन सारख्या इंटरफेसची अंमलबजावणी लिहा जी लांबलचक स्ट्रिंग मिळवते. कार्य 5. तीन फ्लोटिंग-पॉइंट संख्या: a, b, आणि c आणि एक फ्लोटिंग-पॉइंट क्रमांक मिळविणाऱ्या पद्धतीसह कार्यात्मक इंटरफेस लिहा. लॅम्बडा अभिव्यक्ती म्हणून अशा इंटरफेसची अंमलबजावणी लिहा जी भेदभाव परत करते. जर तुम्ही विसरलात तर ते आहे D = b^2 — 4ac. टास्क 6. टास्क 5 मधील फंक्शनल इंटरफेस वापरून, एक लॅम्बडा एक्स्प्रेशन लिहा जे चे परिणाम मिळवते a * b^c. जावा मधील लॅम्बडा अभिव्यक्तींचे स्पष्टीकरण. उदाहरणे आणि कार्यांसह. भाग 2
टिप्पण्या
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION