प्रश्न चिह्न के पीछे क्या छिपा है? Kotlin में nullable में गोता लगाते हैं
\n\nक्या आपने कभी Java में लिखा है और सबसे अनुपयुक्त क्षण में NullPointerException पकड़ा है? यदि हाँ — तो आप जानते हैं कि यह कितना दर्दनाक है। Kotlin डेवलपर्स ने इस समस्या को हमेशा के लिए हल कर दिया, null safety को केवल एक फीचर नहीं, बल्कि भाषा का दर्शन बना दिया। लेकिन शुरुआती लोग अक्सर इस सवाल से डरते हैं: "Kotlin में, nullable मानों को संदर्भित या परिवर्तित करने का idiomatic तरीका क्या है?" (Stack Overflow पर यही सबसे लोकप्रिय प्रश्न है)।
आज हम nullable के साथ काम करने के सभी idioms को समझेंगे: सरल ?. से लेकर चालाक let और जादुई !! तक। और सबसे महत्वपूर्ण — हम अंदर झांकेंगे ताकि समझ सकें कि यह बाइट-कोड स्तर पर कैसे काम करता है। चलिए शुरू करते हैं!
संक्षिप्त परिचय: nullable क्या है?
\n\nKotlin में प्रकार दो शिविरों में विभाजित होते हैं: nullable (जो null हो सकते हैं) और non-nullable (जो नहीं हो सकते)। यदि आप var name: String = null लिखते हैं — कंपाइलर एक त्रुटि देगा। लेकिन var name: String? = null — ठीक है। प्रश्न चिह्न एक मार्कर है जो कहता है: "अरे कंपाइलर, मुझे पता है कि यहाँ खाली हो सकता है, मत डाँटो"।
लेकिन इसके साथ कैसे काम करें? केवल if के माध्यम से null की जाँच करना — यह उबाऊ है और Kotlin शैली में नहीं है। आइए वास्तविक उपकरणों को देखें।
बचाव तिकड़ी: ?, ?: और ?.
\n\nKotlin तीन स्तंभ प्रदान करता है जिन पर nullable के साथ सारा काम टिका है। उन्हें याद रखें — वे आपको डिबगिंग के घंटे बचाएंगे।
\n\n1. Safe call operator (?.)
\n\nयह आपके कोड में सबसे आम मेहमान है। safe call ऑपरेटर केवल तभी मेथड या प्रॉपर्टी को कॉल करने की अनुमति देता है जब ऑब्जेक्ट null के बराबर न हो। यदि ऑब्जेक्ट null है — ऑपरेटर null लौटाएगा, और कोई अपवाद नहीं होगा।
\n\nval user: User? = null\nval name: String? = user?.name // name = null, कोई त्रुटि नहीं\n\nअंदरूनी रूप से, यह बाइट-कोड में बदल जाता है जो null की सामान्य जाँच और सशर्त कॉल करता है। कोई जादू नहीं, केवल सुरक्षा।
\n\n2. Elvis operator (?:)
\n\nएल्विस आपका मित्र है जब आपको डिफ़ॉल्ट मान डालने की आवश्यकता होती है। यदि बायाँ भाग null नहीं है — इसे लें, अन्यथा — दायाँ भाग।
\n\nval name: String? = null\nval displayName: String = name ?: "अतिथि" // "अतिथि"\n\nएल्विस का उपयोग फ़ंक्शन से जल्दी बाहर निकलने के लिए भी किया जा सकता है:
\n\nfun getUserName(user: User?): String {\n val name = user?.name ?: return "अनाम"\n return name\n}\n\n3. Not-null assertion (!!)
\n\nयह एक विद्रोही ऑपरेटर है। यह कहता है: "मुझे यकीन है कि यहाँ null नहीं है, और मैं मरने को तैयार हूँ (अर्थात, NPE फेंकने के लिए) अगर मैं गलत हूँ"। इसका उपयोग सावधानी से करें, केवल तभी जब 100% निश्चित हों।
\n\nval user: User? = getUserFromDatabase() // हमें यकीन है कि वह मौजूद है\nval name: String = user!!.name\n\nअंदरूनी रूप से !! null होने पर NullPointerException फेंकने वाली सामान्य जाँच में संकलित होता है। कुछ भी जटिल नहीं, लेकिन खतरनाक।
Idiomatic तरीका: let, run, apply और कंपनी
\n\nअब हम सबसे दिलचस्प भाग पर आते हैं। Stack Overflow पर प्रश्न बिल्कुल इसी बारे में है: nullable मानों को idiomatic रूप से कैसे परिवर्तित करें। उत्तर — मानक पुस्तकालय से एक्सटेंशन फ़ंक्शन।
\n\nlet — nullable परिवर्तनों का राजा
\n\nlet फ़ंक्शन कोड ब्लॉक को केवल तभी निष्पादित करता है जब ऑब्जेक्ट null न हो। ब्लॉक के अंदर, ऑब्जेक्ट it के रूप में उपलब्ध है (या इसे पुनः नाम दिया जा सकता है)।
val user: User? = getUser()\nuser?.let { \n println("उपयोगकर्ता का नाम: ${it.name}")\n // यहाँ it — गारंटीकृत रूप से null नहीं है\n}\n\nयह केवल गैर-null मान पर कार्रवाई करने का idiomatic तरीका है। let के बिना, आपको लिखना होगा:
if (user != null) {\n println("उपयोगकर्ता का नाम: ${user.name}")\n}