सबसे पहले, आपको कोटलिन में नल सुरक्षा के बारे में सभी पढ़ना चाहिए जो मामलों को अच्छी तरह से कवर करता है।
कोटलिन में, आप यह सुनिश्चित नहीं होने के बिना एक अशक्त मान तक नहीं पहुँच सकते null
( शर्तों में अशक्तता की जाँच करना ), या यह सुनिश्चित करना कि यह निश्चित रूप से निश्चित ऑपरेटरnull
का उपयोग नहीं कर रहा !!
है , इसे ?.
सुरक्षित कॉल के साथ एक्सेस करना , या अंतिम रूप से ऐसा कुछ देना जो संभवतः null
है ?:
एल्विस ऑपरेटर का उपयोग करके डिफ़ॉल्ट मान ।
आपके प्रश्न में आपके 1 मामले के लिए आपके पास इनमें से किसी एक का उपयोग करने वाले कोड के इरादे के आधार पर विकल्प हैं, और सभी मुहावरेदार हैं, लेकिन अलग-अलग परिणाम हैं:
val something: Xyz? = createPossiblyNullXyz()
// access it as non-null asserting that with a sure call
val result1 = something!!.foo()
// access it only if it is not null using safe operator,
// returning null otherwise
val result2 = something?.foo()
// access it only if it is not null using safe operator,
// otherwise a default value using the elvis operator
val result3 = something?.foo() ?: differentValue
// null check it with `if` expression and then use the value,
// similar to result3 but for more complex cases harder to do in one expression
val result4 = if (something != null) {
something.foo()
} else {
...
differentValue
}
// null check it with `if` statement doing a different action
if (something != null) {
something.foo()
} else {
someOtherAction()
}
"यह क्यों काम करता है जब अशक्त जाँच की जाती है" स्मार्ट कास्ट पर नीचे की पृष्ठभूमि की जानकारी पढ़ें ।
Map
यदि आप एक डेवलपर के रूप में सवाल में अपने 2 मामले के लिए , यदि आप एक डेवलपर के रूप में परिणाम कभी नहीं होने के बारे में सुनिश्चित कर रहे हैं, तो सुनिश्चित null
करें !!
कि ऑपरेटर का उपयोग एक जोर के रूप में करें:
val map = mapOf("a" to 65,"b" to 66,"c" to 67)
val something = map.get("a")!!
something.toLong() // now valid
या किसी अन्य मामले में, जब मानचित्र COULD वापस आता है, लेकिन आप एक डिफ़ॉल्ट मान प्रदान कर सकते हैं, तो Map
अपने आप में एक getOrElse
विधि है :
val map = mapOf("a" to 65,"b" to 66,"c" to 67)
val something = map.getOrElse("z") { 0 } // provide default value in lambda
something.toLong() // now valid
पृष्ठभूमि की जानकारी:
नोट: नीचे दिए गए उदाहरणों में मैं व्यवहार को स्पष्ट करने के लिए स्पष्ट प्रकारों का उपयोग कर रहा हूं। प्रकार के अनुमान के साथ, आमतौर पर प्रकार स्थानीय चर और निजी सदस्यों के लिए छोड़ा जा सकता है।
!!
यकीन है कि ऑपरेटर के बारे में अधिक
!!
ऑपरेटर का दावा है कि मूल्य नहीं है null
या एक एनपीई फेंकता है। इसका उपयोग उन मामलों में किया जाना चाहिए जहां डेवलपर गारंटी दे रहा है कि मूल्य कभी नहीं होगा null
। इसे एक चतुर के रूप में एक मुखर के रूप में सोचो ।
val possibleXyz: Xyz? = ...
// assert it is not null, but if it is throw an exception:
val surelyXyz: Xyz = possibleXyz!!
// same thing but access members after the assertion is made:
possibleXyz!!.foo()
और पढ़ें: !! निश्चित संचालक
null
चेकिंग और स्मार्ट कास्ट के बारे में अधिक
यदि आप null
चेक के साथ एक अशक्त प्रकार तक पहुंच की रक्षा करते हैं , तो कंपाइलर स्मार्ट हो जाएगा बयान के शरीर के भीतर मूल्य गैर-अशक्त होने के लिए। कुछ जटिल प्रवाह हैं जहां ऐसा नहीं हो सकता है, लेकिन सामान्य मामलों के लिए यह ठीक काम करता है।
val possibleXyz: Xyz? = ...
if (possibleXyz != null) {
// allowed to reference members:
possiblyXyz.foo()
// or also assign as non-nullable type:
val surelyXyz: Xyz = possibleXyz
}
या यदि आप एक is
अशक्त प्रकार के लिए एक जाँच करते हैं:
if (possibleXyz is Xyz) {
// allowed to reference members:
possiblyXyz.foo()
}
और 'जब' भावों के लिए भी वही सुरक्षित कास्ट है:
when (possibleXyz) {
null -> doSomething()
else -> possibleXyz.foo()
}
// or
when (possibleXyz) {
is Xyz -> possibleXyz.foo()
is Alpha -> possibleXyz.dominate()
is Fish -> possibleXyz.swim()
}
कुछ चीजें चर के बाद के उपयोग के लिए स्मार्ट कास्टnull
को चेक की अनुमति नहीं देती हैं । ऊपर दिया गया उदाहरण एक स्थानीय चर का उपयोग करता है जो किसी भी तरह से अनुप्रयोग के प्रवाह में उत्परिवर्तित नहीं हो सकता था, चाहे या इस चर को एक में उत्परिवर्तित करने का कोई अवसर नहीं था । लेकिन, अन्य मामलों में जहां कंपाइलर प्रवाह विश्लेषण की गारंटी नहीं दे सकता है, यह एक त्रुटि होगी:val
var
null
var nullableInt: Int? = ...
public fun foo() {
if (nullableInt != null) {
// Error: "Smart cast to 'kotlin.Int' is impossible, because 'nullableInt' is a mutable property that could have been changed by this time"
val nonNullableInt: Int = nullableInt
}
}
चर nullableInt
का जीवनचक्र पूरी तरह से दिखाई नहीं देता है और अन्य थ्रेड्स से असाइन किया जा सकता है, null
चेक को एक गैर-अशक्त मान में स्मार्ट कास्ट नहीं किया जा सकता है । वर्कअराउंड के लिए नीचे "सुरक्षित कॉल" विषय देखें।
एक अन्य मामला जिस पर भरोसा नहीं किया जा सकता है उसे स्मार्ट कास्ट द्वारा म्यूट नहीं किया जा सकता है जो val
एक ऑब्जेक्ट पर एक कस्टम गेट्टर है। इस मामले में, संकलक के पास कोई दृश्यता नहीं है कि मूल्य क्या उत्परिवर्तित करता है और इसलिए आपको एक त्रुटि संदेश मिलेगा:
class MyThing {
val possibleXyz: Xyz?
get() { ... }
}
// now when referencing this class...
val thing = MyThing()
if (thing.possibleXyz != null) {
// error: "Kotlin: Smart cast to 'kotlin.Int' is impossible, because 'p.x' is a property that has open or custom getter"
thing.possiblyXyz.foo()
}
और पढ़ें: स्थितियों में अशक्त के लिए जाँच
?.
सुरक्षित कॉल ऑपरेटर के बारे में अधिक
सुरक्षित कॉल ऑपरेटर शून्य हो जाता है यदि बाईं ओर का मान शून्य है, अन्यथा दाईं ओर अभिव्यक्ति का मूल्यांकन करना जारी रखता है।
val possibleXyz: Xyz? = makeMeSomethingButMaybeNullable()
// "answer" will be null if any step of the chain is null
val answer = possibleXyz?.foo()?.goo()?.boo()
एक अन्य उदाहरण जहां आप किसी सूची को पुनरावृत्त करना चाहते हैं, लेकिन केवल null
खाली और खाली न होने पर, फिर से सुरक्षित कॉल ऑपरेटर काम में आता है:
val things: List? = makeMeAListOrDont()
things?.forEach {
// this loops only if not null (due to safe call) nor empty (0 items loop 0 times):
}
ऊपर दिए गए उदाहरणों में से एक में हमारे पास एक मामला था जहां हमने एक if
जांच की थी लेकिन मौका एक और धागा मूल्य को उत्परिवर्तित करता है और इसलिए कोई स्मार्ट कास्ट नहीं है । हम इसे let
हल करने के लिए फ़ंक्शन के साथ सुरक्षित कॉल ऑपरेटर का उपयोग करने के लिए इस नमूने को बदल सकते हैं :
var possibleXyz: Xyz? = 1
public fun foo() {
possibleXyz?.let { value ->
// only called if not null, and the value is captured by the lambda
val surelyXyz: Xyz = value
}
}
और पढ़ें: सुरक्षित कॉल
?:
एल्विस ऑपरेटर के बारे में अधिक
एल्विस ऑपरेटर आपको एक वैकल्पिक मूल्य प्रदान करने की अनुमति देता है जब ऑपरेटर के बाईं ओर एक अभिव्यक्ति है null
:
val surelyXyz: Xyz = makeXyzOrNull() ?: DefaultXyz()
इसके कुछ रचनात्मक उपयोग भी हैं, उदाहरण के लिए जब कुछ होता है तो एक अपवाद को फेंक दें null
:
val currentUser = session.user ?: throw Http401Error("Unauthorized")
या एक समारोह से जल्दी लौटने के लिए:
fun foo(key: String): Int {
val startingCode: String = codes.findKey(key) ?: return 0
// ...
return endingValue
}
और अधिक पढ़ें: एल्विस ऑपरेटर
संबंधित कार्यों के साथ अशक्त संचालक
Kotlin stdlib में उन कार्यों की एक श्रृंखला है जो ऊपर वर्णित ऑपरेटरों के साथ वास्तव में अच्छी तरह से काम करते हैं। उदाहरण के लिए:
// use ?.let() to change a not null value, and ?: to provide a default
val something = possibleNull?.let { it.transform() } ?: defaultSomething
// use ?.apply() to operate further on a value that is not null
possibleNull?.apply {
func1()
func2()
}
// use .takeIf or .takeUnless to turn a value null if it meets a predicate
val something = name.takeIf { it.isNotBlank() } ?: defaultName
val something = name.takeUnless { it.isBlank() } ?: defaultName
संबंधित विषय
कोटलिन में, अधिकांश एप्लिकेशन null
मूल्यों से बचने की कोशिश करते हैं, लेकिन यह हमेशा संभव नहीं होता है। और कभी null
- कभी एकदम सही समझ में आता है। सोचने के लिए कुछ दिशानिर्देश:
कुछ मामलों में, यह विभिन्न रिटर्न प्रकारों को वारंट करता है जिसमें विधि कॉल की स्थिति और परिणाम सफल होने पर शामिल होता है। परिणाम जैसे पुस्तकालय आपको एक सफलता या विफलता परिणाम प्रकार देते हैं जो आपके कोड को भी शाखा दे सकते हैं। और कोटलिन के लिए प्रोमिस लाइब्रेरी, जिसे कोवंत कहा जाता है, वादों के रूप में ही करता है।
रिटर्न प्रकारों के लिए संग्रह हमेशा एक के बजाय एक खाली संग्रह लौटाते हैं null
, जब तक कि आपको "मौजूद नहीं" के तीसरे राज्य की आवश्यकता होती है। कोटलिन के पास इन खाली मूल्यों को बनाने emptyList()
याemptySet()
बनाने के लिए सहायक कार्य हैं।
ऐसे तरीकों का उपयोग करते समय जो एक अशक्त मान लौटाते हैं जिसके लिए आपके पास एक डिफ़ॉल्ट या विकल्प है, एक डिफ़ॉल्ट मान प्रदान करने के लिए एल्विस ऑपरेटर का उपयोग करें। एक Map
उपयोग के मामले में getOrElse()
जो Map
विधि के बजाय एक डिफ़ॉल्ट मान उत्पन्न करने की अनुमति देता है get()
जो एक अशक्त मान लौटाता है। उसी के लिएgetOrPut()
जब जावा से तरीकों को ओवरराइड करना जहां कोटलिन जावा कोड की अशक्तता के बारे में निश्चित नहीं है, तो आप हमेशा ?
अपने ओवरराइड से अशक्तता को छोड़ सकते हैं यदि आप सुनिश्चित हैं कि हस्ताक्षर और कार्यक्षमता क्या होनी चाहिए। इसलिए आपकी ओवरराइड विधि अधिक null
सुरक्षित है। कोटलिन में जावा इंटरफेस को लागू करने के लिए समान है, जो आप जानते हैं कि मान्य होने की अशक्तता को बदलें।
उन कार्यों को देखें जो पहले से ही मदद कर सकते हैं, जैसे कि String?.isNullOrEmpty()
और String?.isNullOrBlank()
जो कि एक अशक्त मूल्य पर सुरक्षित रूप से काम कर सकता है और वह कर सकता है जो आप उम्मीद करते हैं। वास्तव में, आप मानक पुस्तकालय में किसी भी अंतराल को भरने के लिए अपने स्वयं के एक्सटेंशन जोड़ सकते हैं।
मुखर पुस्तकालय में checkNotNull()
और जैसे requireNotNull()
मानक कार्य करता है ।
सहायक कार्य जैसे filterNotNull()
कि संग्रह से नल हटाते हैं, या listOfNotNull()
संभवतः null
मूल्य से शून्य या एकल आइटम सूची वापस करने के लिए ।
एक सुरक्षित ( अशक्त ) कास्ट ऑपरेटर है और साथ ही यह भी संभव नहीं है कि एक डाली गैर अशक्त प्रकार वापसी नल के लिए अनुमति देता है। लेकिन मेरे पास इसके लिए वैध उपयोग का मामला नहीं है जो ऊपर उल्लिखित अन्य विधियों द्वारा हल नहीं किया गया है।