क्या अशक्त बुरा डिजाइन लौट रहा है? [बन्द है]


127

मैंने कुछ आवाज़ें यह कहते हुए सुनी हैं कि तरीकों से लौटाए गए शून्य मान के लिए जाँच करना खराब डिज़ाइन है। मैं इसके लिए कुछ कारण सुनना चाहूंगा।

स्यूडोकोड:

variable x = object.method()
if (x is null) do something

13
विस्तृत: ये लोग कहाँ हैं जो कहते हैं कि यह बुरा है? लिंक?
जुल्लम

2
यदि विधि ऐसी चीज है जिस पर आपका नियंत्रण है, तो आप यह सुनिश्चित करने के लिए इकाई परीक्षण कर सकते हैं कि यह कभी भी अशक्त नहीं लौटे, अन्यथा, मुझे नहीं लगता कि यह कॉल करने के बाद यह शून्य है या नहीं, यह जांचने के लिए एक बुरा अभ्यास क्यों होगा; हो सकता है कि अशक्त वापस लौटने के लिए उस पद्धति पर एक बुरा अभ्यास हो, लेकिन आपको अपने कोड की रक्षा करनी होगी
BlackTigerX

9
अपवादों को उठाना सिर्फ इसलिए कि लौटाया जाने वाला कोई डेटा अविश्वसनीय रूप से कष्टप्रद नहीं है। सामान्य कार्यक्रम प्रवाह को अपवाद नहीं फेंकना चाहिए।
थोरिन

4
@ डेविड: यही तो मैंने सच कहा है। यदि किसी विधि को डेटा वापस करना चाहिए, लेकिन कोई भी नहीं है, तो इसका मतलब है कि कुछ गलत भी हो गया है। यह सामान्य कार्यक्रम प्रवाह नहीं है :)
थोरारिन

2
@ थोरारिन: "सामान्य" कार्यक्रम प्रवाह काफी फैला हुआ अवधारणा है: तर्क के लिए वास्तव में ठोस आधार नहीं है।
टॉमिस्लाव नैक-अल्फेयरविच

जवाबों:


206

अशक्त नहीं लौटने के पीछे तर्क यह है कि आपको इसके लिए जांच करने की आवश्यकता नहीं है और इसलिए आपके कोड को वापसी मूल्य के आधार पर एक अलग पथ का पालन करने की आवश्यकता नहीं है । आप नल ऑब्जेक्ट पैटर्न की जांच करना चाहते हैं जो इस पर अधिक जानकारी प्रदान करता है।

उदाहरण के लिए, अगर मैं जावा में एक विधि को परिभाषित करता हूं जो एक संग्रह लौटाता है तो मैं आमतौर पर रिक्त संग्रह (यानी Collections.emptyList()) को शून्य के बजाय वापस करना पसंद करूंगा क्योंकि इसका मतलब है कि मेरा क्लाइंट कोड क्लीनर है; जैसे

Collection<? extends Item> c = getItems(); // Will never return null.

for (Item item : c) { // Will not enter the loop if c is empty.
  // Process item.
}

... जो क्लीनर है:

Collection<? extends Item> c = getItems(); // Could potentially return null.

// Two possible code paths now so harder to test.
if (c != null) {
  for (Item item : c) {
    // Process item.
  }
}

6
हां, अशक्त लौटने से बेहतर है और ग्राहक को मामले से निपटने की याद है।
djna

10
मैं ख़ुशी से सहमत हूँ कि जब यह खाली कंटेनर (या तार) के विकल्प के रूप में उपयोग किया जाता है, तो अशक्त लौट आना पागल है। हालांकि यह आम मामला नहीं है।
एमएसलेट्स

2
मेरे लिए नल ऑब्जेक्ट पैटर्न के लिए +1। इसके अलावा जब मैं वास्तव में अशक्त होना चाहता हूं, तो मैं इसे स्पष्ट करने के लिए getCustomerOrNull () जैसी विधि का नामकरण कर रहा हूं। मुझे लगता है कि जब पाठक कार्यान्वयन को देखना नहीं चाहता है तो एक विधि को अच्छी तरह से नाम दिया गया है।
माइक वैलेंटी

4
टिप्पणी '// दो संभव कोड पथ अब' सही नहीं है; आपके पास दो कोड पथ हैं। हालाँकि, आपके पहले उदाहरण में नल संग्रह ऑब्जेक्ट के साथ, 'null' कोड पथ छोटा है। आपके पास अभी भी दो रास्ते हैं, और आपको अभी भी दो रास्तों का परीक्षण करने की आवश्यकता है।
Frerich Raabe

1
@MSalters - यकीनन OO भाषाओं में हर चर nullएक "कंटेनर" है, जिसमें वस्तुओं के लिए शून्य या एक संकेत होता है। (यह निश्चित रूप से है कि यह Maybeउन मामलों में हास्केल द्वारा स्पष्ट रूप से कैसे तैयार किया गया है , और ऐसा करने के लिए सभी बेहतर है।)
एंड्रीज डॉयल

71

यहाँ कारण है।

में स्वच्छ कोड रॉबर्ट मार्टिन द्वारा वे लिखते हैं कि लौटने अशक्त बुरा डिजाइन जब आप के बजाय लौट सकते हैं, कहते हैं, खाली सरणी है। चूंकि अपेक्षित परिणाम एक सरणी है, क्यों नहीं? यह आपको बिना किसी अतिरिक्त शर्त के परिणाम में पुनरावृति करने में सक्षम करेगा। यदि यह पूर्णांक है, तो शायद 0 पर्याप्त होगा, यदि यह एक हैश, खाली हैश है। आदि।

आधार कॉलिंग कोड को तुरंत मुद्दों से निपटने के लिए मजबूर नहीं करना है। कॉलिंग कोड शायद उनके साथ खुद को चिंता नहीं करना चाहता। यही कारण है कि कई मामलों में अपवाद शून्य से बेहतर है।


2
यह इस उत्तर में उल्लिखित अशक्त वस्तु पैटर्न है: stackoverflow.com/questions/1274792/…
स्कॉट डोरमैन

यहाँ विचार यह है कि गलती पर, आप सामान्य रूप से जो भी वस्तु टाइप करेंगे, उसका एक खाली / खाली संस्करण वापस कर देंगे। एक खाली सरणी या स्ट्रिंग उन मामलों के लिए काम करेगी, उदाहरण के लिए। "NULL" वापस करना तब उचित होगा जब आप सामान्य रूप से एक पॉइंटर लौटाएंगे (क्योंकि NULL अनिवार्य रूप से एक खाली पॉइंटर है)। सामान्य रूप से रिटर्न करने वाले फ़ंक्शन से त्रुटि पर NULL लौटना, कहना, एक हैश भ्रमित हो सकता है। कुछ भाषाएं दूसरों की तुलना में इसे बेहतर तरीके से संभालती हैं लेकिन सामान्य तौर पर, स्थिरता सबसे अच्छा अभ्यास है।
बटा

जब तक कि त्रुटि किसी तरह प्रवाह (जो एक अच्छा अभ्यास नहीं है) या एपीआई या इंटरफ़ेस में अमूर्त नहीं है, तब तक आप गलती से वापस नहीं आते हैं। त्रुटियां किसी भी स्तर पर प्रचारित करने के लिए हैं, जिस पर आप इसे पकड़ने का निर्णय लेते हैं, इसलिए आपको कॉलिंग के संदर्भ में इससे निपटने की आवश्यकता नहीं है। वे डिफ़ॉल्ट रूप से अशक्त-ऑब्जेक्ट-पैटर्न-अनुकूल हैं।
मैक्स चेर्नाक

दुर्भाग्य से, कॉलिंग कोड हमेशा एक खाली संग्रह के मामले पर विचार नहीं करता है (जैसे कि यह शून्य मामले पर विचार नहीं करता है)। यह एक समस्या हो सकती है या नहीं।
श्रीधर सरनोबत

38

अशक्त लौटने के अच्छे उपयोग:

  • यदि अशक्त एक वैध कार्यात्मक परिणाम है, उदाहरण के लिए: FindFirstObjectThatNeedsProcessing () नहीं मिलने पर अशक्त लौट सकता है और कॉलर को तदनुसार जांच करनी चाहिए।

खराब उपयोग: जैसे असाधारण स्थितियों को बदलने या छिपाने की कोशिश करना:

  • पकड़ (...) और अशक्त वापसी
  • API निर्भरता प्रारंभ विफल रहा
  • डिस्क के स्थान से बाहर
  • अमान्य इनपुट पैरामीटर्स (प्रोग्रामिंग त्रुटि, इनपुट्स को कॉलर द्वारा सैनिटाइज़ किया जाना चाहिए)
  • आदि

उन मामलों में अपवाद छोड़ना अधिक पर्याप्त है:

  • एक शून्य वापसी मूल्य कोई सार्थक त्रुटि जानकारी प्रदान करता है
  • तत्काल कॉलर सबसे अधिक संभावना त्रुटि स्थिति को संभाल नहीं सकता है
  • इस बात की कोई गारंटी नहीं है कि कॉलर अशक्त परिणामों के लिए जाँच कर रहा है

हालाँकि, अपवाद का उपयोग सामान्य प्रोग्राम संचालन स्थितियों को संभालने के लिए नहीं किया जाना चाहिए जैसे:

  • अमान्य उपयोगकर्ता नाम / पासवर्ड (या कोई भी उपयोगकर्ता-प्रदत्त इनपुट)
  • ब्रेकिंग लूप्स या गैर-स्थानीय गोटो के रूप में

7
"अमान्य उपयोगकर्ता नाम" एक अपवाद के लिए एक अच्छे कारण की तरह लगता है, हालांकि।
थिलो

11
अमान्य लॉगिन / पासवर्ड दर्ज करने वाले उपयोगकर्ताओं को एक असाधारण स्थिति के रूप में नहीं माना जाना चाहिए, जो सामान्य कार्यक्रम संचालन का हिस्सा है। हालांकि, प्रमाणीकरण प्रणाली प्रतिक्रिया करने में विफल (उदाहरण के लिए सक्रिय निर्देशिका) एक असाधारण स्थिति है।
जीरो कॉनसेप्ट


2
मैं कहता हूँ कि यह निर्भर करता है: boolean login(String,String)ठीक लगता है और ऐसा ही होता हैAuthenticationContext createAuthContext(String,String) throws AuthenticationException
sfussenegger

1
आपके उदाहरण में, यदि कोई पहली वस्तु नहीं है जिसे प्रसंस्करण की आवश्यकता है, तो उस मामले को संभालने के दो उचित तरीके हैं। पहला नल ऑब्जेक्ट पैटर्न है। एक अंतिम उपवर्ग बनाएं जो कक्षा के गैर-मौजूद संस्करण का प्रतिनिधित्व करता है। यह उचित चूक और फेंकता अपवाद है जब बकवास कार्यों का अनुरोध किया जाता है। अन्य तकनीक विकल्प है। यह वही है जो Java8 और Scala में उपलब्ध है। इनमें से कोई भी डेवलपर्स का इरादा दिखाता है। अशक्त इरादे नहीं दिखा सकता क्योंकि इसके बहुत सारे संभावित अर्थ हैं। ** इरादे दिखाना ** कोड का सबसे महत्वपूर्ण पहलू है।
स्कॉट एम गार्डनर

29

हां, NULL लौटना एक भयानक डिजाइन है , वस्तु-उन्मुख दुनिया में। संक्षेप में, NULL उपयोग की ओर जाता है:

  • तदर्थ त्रुटि से निपटने (अपवादों के बजाय)
  • अस्पष्ट शब्दार्थ
  • तेजी से असफल होने के बजाय धीमा
  • ऑब्जेक्ट थिंकिंग के बजाय कंप्यूटर सोच
  • उत्परिवर्तनीय और अपूर्ण वस्तुएं

विस्तृत विवरण के लिए इस ब्लॉग पोस्ट की जाँच करें: http://www.yegor256.com/2014/05/13/why-null-is-bad.html । मेरी पुस्तक एलिगेंट ऑब्जेक्ट्स , धारा 4.1 में अधिक।


2
मैं दृढ़ता से सहमत हूं। मुझे अशक्त ऑब्जेक्ट पैटर्न भी पसंद नहीं है जो एक 'व्हाइटवॉश' देरी रणनीति प्रतीत होता है। या तो आपका तरीका हमेशा सफल होता है या ऐसा नहीं होता है। अगर यह हमेशा सफल होना चाहिए, तो फेंक देना चाहिए। यदि यह सफल नहीं हो सकता है, तो विधि डिजाइन तो उपभोक्ता जानता है, जैसे bool TryGetBlah(out blah)या FirstOrNull()या MatchOrFallback(T fallbackValue)
ल्यूक पुप्लेट

मुझे भी रिटर्न नल पसंद नहीं है। आप लक्षणों को जड़ से अलग कर रहे हैं, जिससे डिबगिंग कठिन हो जाती है। या तो एक अपवाद (तेजी से विफल) फेंकें, या एक बॉलर विधि को कॉल करें जो पहले बूलियन लौटाता है (उदाहरण के लिए isEmpty()) और केवल अगर यह सच है तो विधि को कॉल करें। लोग दूसरे के खिलाफ तर्क देते हैं कि यह खराब प्रदर्शन है - लेकिन जैसा कि यूनिक्स दर्शन कहते हैं, "मशीन समय पर मानव समय को महत्व देते हैं" (यानी तुच्छ धीमा प्रदर्शन डेवलपर्स डिबगिंग कोड की तुलना में कम समय बर्बाद करता है जो कि गंभीर त्रुटियां दे रहा है)।
श्रीधर सरनोबत

22

कौन कहता है कि यह खराब डिजाइन है?

नल की जांच करना एक आम बात है, यहां तक ​​कि प्रोत्साहित भी किया जाता है, अन्यथा आप हर जगह NullReferenceException का जोखिम चलाते हैं। जब आप की आवश्यकता नहीं है, तो इसे अपवाद से फेंकने की अपेक्षा त्रुटि को संभालना बेहतर है।


11
+1। कोड है कि समस्याओं के लिए अपवाद है कि मौके पर कम किया जा सकता है मुझे दुखी करता है।
jkeys

6
जब कोडर्स नल के लिए जाँच करना भूल जाते हैं और फिर रहस्यमय नल सूचक अपवाद प्राप्त करते हैं, तो आपको कितना दुख होता है? जाँच किए गए अपवाद, जहां कंपाइलर उपयोगकर्ता को याद दिलाता है कि उन्होंने त्रुटि स्थितियों से निपटने के लिए कोडिंग त्रुटियों के taht वर्ग से बचें।
djna

3
@ डजना: मुझे लगता है कि यह भी दुखद है, लेकिन मैंने पाया है कि एक ही प्रकार के कोडर जो "भूल" करने के लिए नल की जांच करते हैं, वे हैं जो चेक किए गए अपवादों से निपटने पर अक्सर उन्हें निगलते हैं।
रैंडी

5
शून्य-चेक ​​की अनुपस्थिति से खाली कैच ब्लॉक की मौजूदगी का पता लगाना आसान है।
प्रेस्टन

20
@ प्रेस्टन: मैं दृढ़ता से असहमत हूं। जब यह दुर्घटनाग्रस्त हो जाए, तो आप तुरंत जांच करेंगे कि क्या हुआ है। वर्षों से रहस्यमय और सूक्ष्म त्रुटियों को
प्रचारित किया जा सकता है

18

अब तक आपने जो कहा है, उसके आधार पर, मुझे लगता है कि पर्याप्त जानकारी नहीं है।

एक CreateWidget () विधि से अशक्त लौटना बुरा लगता है।

FindFooInBar () विधि से अशक्त लौटना ठीक लगता है।


4
मेरे सम्मेलन के समान: एकल आइटम प्रश्न - Create... एक नया उदाहरण देता है, या फेंकता है ; Get...एक अपेक्षित मौजूदा उदाहरण देता है, या फेंकता है ; GetOrCreate...यदि कोई मौजूद नहीं है या फेंकता है, तो एक मौजूदा उदाहरण, या नया उदाहरण लौटाता है ; Find...एक मौजूदा उदाहरण देता है, अगर यह मौजूद है, याnullसंग्रह क्वेरीज़ के लिए - Get... हमेशा एक संग्रह लौटाता है, जो कोई मेल नहीं मिलने पर खाली होता है।
जोहान गेरेल

येगोर 256 और हेकिनिन के उत्तर में दिए गए कारणों के लिए NULL का बुरा, एक वैध लेकिन खाली वस्तु वापस करना तर्क को सरल करता है
Rob11311


10

यह उस भाषा पर निर्भर करता है जिसका आप उपयोग कर रहे हैं। यदि आप C # जैसी भाषा में हैं, जहाँ किसी मान की कमी को इंगित करने का मुहावरेदार तरीका है, अशक्त लौटना, तो यदि आपके पास कोई मान नहीं है, तो अशक्त लौटना एक अच्छा डिज़ाइन है। वैकल्पिक रूप से, हास्केल जैसी भाषाओं में जो इस मामले के लिए शायद मुदित का उपयोग करते हैं, फिर अशक्त लौट आना एक बुरा डिजाइन होगा (यदि यह भी संभव था)।


2
शायद मोनद का उल्लेख करने के लिए +1। मुझे लगता है कि nullसी # और जावा जैसी भाषाओं की परिभाषा अक्सर अतिभारित होती है और डोमेन में कुछ अर्थ दिया जाता है। यदि आप nullभाषा स्पेक्स में कीवर्ड को देखते हैं, तो इसका मतलब है "अमान्य सूचक"। यह संभावना किसी भी समस्या डोमेन में कुछ भी नहीं है।
मैटवेवी

समस्या यह है कि क्या आप नहीं जानते कि यह "लापता मूल्य" है nullया "आरंभीकृत नहीं है"null
CervEd

5

यदि आप सभी उत्तरों को पढ़ते हैं तो यह स्पष्ट हो जाता है कि इस प्रश्न का उत्तर किस तरह की विधि पर निर्भर करता है।

सबसे पहले, जब कुछ असाधारण होता है (IOproblem आदि), तार्किक रूप से अपवादों को फेंक दिया जाता है। जब वास्तव में कुछ असाधारण होता है तो शायद एक अलग विषय के लिए कुछ होता है।

जब भी किसी विधि से अपेक्षा की जाती है कि संभवतः कोई परिणाम नहीं है दो श्रेणियां हैं:

  • यदि तटस्थ मूल्य वापस करना संभव है , तो ऐसा करें
    खाली enumrables, तार आदि अच्छे उदाहरण हैं
  • यदि इस तरह के एक तटस्थ मूल्य मौजूद नहीं है, तो अशक्त वापस आ जाना चाहिए
    जैसा कि उल्लेख किया गया है, विधि को माना जाता है कि संभवतः इसका कोई परिणाम नहीं है, इसलिए यह असाधारण नहीं है, इसलिए अपवाद नहीं फेंकना चाहिए। एक तटस्थ मान संभव नहीं है (उदाहरण के लिए: 0 विशेष रूप से कार्यक्रम के आधार पर एक तटस्थ परिणाम नहीं है)

अनटिल में हमारे पास यह बताने का एक आधिकारिक तरीका है कि कोई फ़ंक्शन शून्य हो सकता है या वापस नहीं आ सकता है, मैं ऐसा करने के लिए नामकरण सम्मेलन करने की कोशिश करता हूं।
जैसे आपके पास ट्राई समथिंग () कन्वेंशन फेल होने की उम्मीद के तरीके हैं, मैं अक्सर अपने तरीकों को नाम देता हूं सेफ समथिंग () जब विधि शून्य के बजाय एक तटस्थ परिणाम देता है।

मैं अभी तक नाम के साथ पूरी तरह से ठीक नहीं हूं, लेकिन कुछ भी बेहतर नहीं कर सका। इसलिए मैं इसके लिए अभी दौड़ रहा हूं।


4

मेरा इस क्षेत्र में एक सम्मेलन है जिसने मुझे अच्छी सेवा दी है

एकल आइटम प्रश्नों के लिए:

  • Create...एक नया उदाहरण देता है, या फेंकता है
  • Get...एक अपेक्षित मौजूदा उदाहरण देता है, या फेंकता है
  • GetOrCreate...यदि कोई मौजूद नहीं है, या फेंकता है, तो एक मौजूदा उदाहरण, या नया उदाहरण लौटाता है
  • Find...एक मौजूदा उदाहरण देता है, अगर यह मौजूद है, याnull

संग्रह प्रश्नों के लिए:

  • Get... हमेशा एक संग्रह लौटाता है, जो खाली है अगर कोई मिलान नहीं [1] आइटम पाए जाते हैं

[१] कुछ मानदंड, स्पष्ट या निहित, फ़ंक्शन नाम या मापदंडों के रूप में दिए गए।


GetOne और FindOne क्यों नहीं मिले तो अलग लौटें?
व्लादिमीर वुकानैक

मैंने अंतर बताया। Getजब मैं उम्मीद करता हूं कि मैं इसका उपयोग करूंगा , तो अगर यह नहीं है, तो यह एक त्रुटि है और मैं फेंक देता हूं - मुझे वापसी मूल्य की जांच करने की आवश्यकता नहीं है। मैं उपयोग करता हूं Findअगर मुझे वास्तव में पता नहीं है कि यह वहां है या नहीं - तो मुझे वापसी मूल्य की जांच करने की आवश्यकता है।
जोहान गेर्ले

3

अपवाद के लिए कर रहे हैं अपवाद अल परिस्थितियों के लिए हैं।

यदि आपके फ़ंक्शन का उद्देश्य किसी दिए गए ऑब्जेक्ट से जुड़ी विशेषता को ढूंढना है, और उस ऑब्जेक्ट में ऐसी कोई विशेषता नहीं है, तो अशक्त वापस आना उचित हो सकता है। यदि ऑब्जेक्ट मौजूद नहीं है, तो अपवाद फेंकना अधिक उपयुक्त हो सकता है। यदि फ़ंक्शन विशेषताओं की सूची को वापस करने के लिए है, और वापस लौटने के लिए कोई भी नहीं है, तो खाली सूची वापस करने से समझ में आता है - आप सभी शून्य विशेषताओं को वापस कर रहे हैं।


1
यदि आप बिना किसी मान के किसी विशेषता का उपयोग करने का प्रयास करते हैं , तो यह एक अपवाद का गुण है। (मैं मान रहा हूं कि आपकी युक्ति विशेषता वैकल्पिक है।) यह जांचने के लिए एक अलग विधि है कि क्या इसका मूल्य निर्धारित किया गया है।
प्रेस्टन

3

यदि ऐसा करना सार्थक है, तो यह किसी तरह से सार्थक है:

public String getEmployeeName(int id){ ..}

इस तरह के मामले में अगर आईडी किसी मौजूदा इकाई के अनुरूप नहीं है, तो यह वापस लौटने के लिए सार्थक है, क्योंकि यह आपको उस मामले को अलग करने की अनुमति देता है जहां कोई मैच वैध त्रुटि से नहीं मिला था।

लोग सोच सकते हैं कि यह बुरा है क्योंकि इसे "विशेष" रिटर्न मान के रूप में दुरुपयोग किया जा सकता है जो एक त्रुटि स्थिति को इंगित करता है, जो इतना अच्छा नहीं है, एक फ़ंक्शन से रिटर्न कोड त्रुटि की तरह थोड़ा सा है, लेकिन भ्रमित क्योंकि उपयोगकर्ता के लिए वापसी की जांच करना है अशक्त, उपयुक्त अपवादों को पकड़ने के बजाय, उदा

public Integer getId(...){
   try{ ... ; return id; }
   catch(Exception e){ return null;}
}

3
हाँ। यदि आपको कोई त्रुटि स्थिति मिली है, तो एक अपवाद फेंकें।
डेविड थॉर्नले

3
यह एक ऐसा मामला है जहां अपवाद को वारंट किया जाएगा। यदि आप किसी ऐसे कर्मचारी के नाम का अनुरोध कर रहे हैं जो मौजूद नहीं है, तो कुछ स्पष्ट रूप से गलत हो रहा है।
थोरिन

मुझे लगता है कि थोड़ा सा शाब्दिक है, थोरारिन-आप मेरे उदाहरण से निश्चित रूप से वक्रोक्ति कर सकते हैं, लेकिन मुझे यकीन है कि आप एक ऐसे फ़ंक्शन के कुछ उदाहरणों की कल्पना कर सकते हैं जो मिलान नहीं होने पर एक मिलान मूल्य या शून्य देता है। कैसे एक हैशटेब में एक कुंजी से मूल्य प्राप्त करने के बारे में? (पहली जगह में उस उदाहरण के बारे में सोचा जाना चाहिए)।
स्टीव बी।

1
एक हैश तालिका एक कुंजी है जो मौजूद नहीं है के लिए अशक्त है। स्वचालित रूप से ऐसा करने का मतलब है कि आप असंगत कोड के बिना शून्य को स्टोर नहीं कर सकते।
RHSeeger 13

3

यह जरूरी नहीं कि एक खराब डिजाइन है - इतने सारे डिजाइन निर्णयों के साथ, यह निर्भर करता है।

यदि विधि का परिणाम कुछ ऐसा है जिसका सामान्य उपयोग में अच्छा परिणाम नहीं होता है, तो वापस लौटना ठीक है:

object x = GetObjectFromCache();   // return null if it's not in the cache

यदि वास्तव में हमेशा एक अशक्त परिणाम होना चाहिए, तो अपवाद फेंकना बेहतर हो सकता है:

try {
   Controller c = GetController();    // the controller object is central to 
                                      //   the application. If we don't get one, 
                                      //   we're fubar

   // it's likely that it's OK to not have the try/catch since you won't 
   // be able to really handle the problem here
}
catch /* ... */ {
}

2
यद्यपि आप एक नैदानिक ​​त्रुटि को वहीं लॉग कर सकते हैं, फिर शायद अपवाद को फिर से हटा दें। कुछ समय पहले विफलता डेटा कैप्चर बहुत मददगार हो सकता है।
djna

या अपवाद को संदेश स्ट्रिंग में नैदानिक ​​जानकारी के साथ एक RuntimeException में लपेटें। जानकारी साथ रखें।
थोरबजोरन राव एंडरसन

अब (2018 में) मैं अब सहमत नहीं हो सकता हूं और ऐसे मामलों में हमें वापसी का पक्ष लेना चाहिएOptional<>
पिओटर मुलर

2

कुछ परिदृश्यों के लिए, आप एक असफलता को जल्द से जल्द नोटिस करना चाहते हैं।

NULL के खिलाफ जाँच करना और प्रोग्रामर त्रुटियों के लिए जोर लगाना या (विफलता के मामले में उपयोगकर्ता या कॉलर त्रुटियों के लिए) फेंकने का मतलब यह हो सकता है कि बाद में क्रैश को ट्रैक करना मुश्किल है, क्योंकि मूल विषम मामला नहीं मिला था।

इसके अलावा, त्रुटियों को अनदेखा करने से सुरक्षा कारनामे हो सकते हैं। शायद नल-नेस इस तथ्य से आया था कि एक बफर ओवरराइट या पसंद किया गया था। अब, आप क्रैश नहीं कर रहे हैं , जिसका अर्थ है कि शोषणकर्ता को आपके कोड को निष्पादित करने का मौका है।


2

आप अशक्त लौटने के लिए क्या विकल्प देखते हैं?

मैं दो मामले देखता हूं:

  • findAnItem (id)। यदि आइटम नहीं मिला तो यह क्या करना चाहिए

इस मामले में हम कर सकते हैं: वापसी नल या एक फेंक दिया (जाँच) अपवाद (या शायद एक आइटम बनाने के लिए और इसे वापस)

  • listItemsMatching (मानदंड) यदि कुछ भी नहीं मिला है तो यह क्या लौटना चाहिए?

इस मामले में हम अशक्त लौट सकते हैं, एक खाली सूची वापस कर सकते हैं या एक अपवाद फेंक सकते हैं।

मेरा मानना ​​है कि वापसी अशक्त विकल्प की तुलना में कम अच्छा हो सकता है क्योंकि ग्राहक को शून्य, प्रोग्रामर भूलने और कोड की जांच करने के लिए याद रखने की आवश्यकता होती है

x = find();
x.getField();  // bang null pointer exception

जावा में, एक चेक किए गए अपवाद को फेंकना, RecordNotFoundException, कंपाइलर को क्लाइंट को केस से निपटने के लिए याद दिलाने की अनुमति देता है।

मुझे लगता है कि खाली सूचियों को लौटाने वाली खोजें काफी सुविधाजनक हो सकती हैं - बस सूची की सभी सामग्रियों के साथ प्रदर्शन को आबाद करें, ओह यह खाली है, कोड "बस काम करता है"।


3
स्थिति को इंगित करने के लिए अपवादों को फेंकना, जो संभवतः कार्यक्रम के सामान्य प्रवाह के दौरान होने की उम्मीद है, वास्तव में बदसूरत कोड की ओर जाता है, सॉर्ट की कोशिश {x = find ()} कैच (RecordNotFound e) {// do stuff}।
क्वांट_देव

खाली सूचियों को वापस करना एक अच्छा समाधान है लेकिन केवल तभी जब विधि संदर्भ में हो जो सूचियों को वापस कर सके। "FindById" स्थितियों के लिए, आपको अशक्त लौटने की आवश्यकता है। मैं RecordNotFound अपवादों को पसंद नहीं करता।
थिलो

तो यह राय में हमारे भिन्नता का क्रूस है। मेरी आँखों में x = find () के बीच की सुंदरता में बहुत अंतर नहीं है; if (x = null) {work} और {do stuff} और पकड़ने का प्रयास करें। और, यदि आवश्यक हो तो मैं कोड शुद्धता के लिए सुंदरता का त्याग करने के लिए तैयार हूं। मेरे जीवन में अक्सर मैं कोड का सामना करता हूं, जहां रिटर्न मानों की जांच नहीं की गई है।
djna

1

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



1

इस धागे के पीछे आधार विचार रक्षात्मक रूप से कार्यक्रम करना है। यानी, अप्रत्याशित के खिलाफ कोड। विभिन्न उत्तरों की एक सरणी है:

अदाम्सकी सुझाव है कि Null Object Pattern को देखें, उस उत्तर के लिए उस सुझाव पर मतदान किया जाए।

माइकल वैलेंटी ने डेवलपर को यह बताने के लिए एक नामकरण सम्मेलन का भी सुझाव दिया कि क्या उम्मीद की जा सकती है। ZeroConcept , अपवाद का एक उचित उपयोग का सुझाव देता है, यदि वह NULL का कारण है। और दूसरे।

यदि हम "नियम" बनाते हैं जिसे हम हमेशा रक्षात्मक प्रोग्रामिंग करना चाहते हैं तो हम देख सकते हैं कि ये सुझाव मान्य हैं।

लेकिन हमारे पास 2 विकास परिदृश्य हैं।

एक डेवलपर द्वारा कक्षाएं "लेखक": लेखक

किसी अन्य (शायद) डेवलपर द्वारा कक्षाएं "भस्म": डेवलपर

भले ही कोई क्लास रिटर्न वैल्यू वाले तरीकों के लिए NULL लौटे या नहीं, डेवलपर को ऑब्जेक्ट के वैध होने पर परीक्षण करने की आवश्यकता होगी।

यदि डेवलपर ऐसा नहीं कर सकता है, तो वह वर्ग / विधि निर्धारक नहीं है। यही है, यदि ऑब्जेक्ट प्राप्त करने के लिए "विधि कॉल" वह नहीं करता है जो वह "विज्ञापन करता है" (जैसे getEmployee) ने अनुबंध को तोड़ दिया है।

एक वर्ग के लेखक के रूप में, मैं हमेशा एक विधि बनाते समय दयालु और रक्षात्मक (और निर्धारक) के रूप में बनना चाहता हूं।

इसलिए यह देखते हुए कि NULL या NULL OBJECT (जैसे कि यदि (NullEmployee.ISVALID के रूप में कर्मचारी) की जाँच की जानी चाहिए और कर्मचारियों के संग्रह के साथ ऐसा करने की आवश्यकता हो सकती है, तो अशक्त वस्तु दृष्टिकोण बेहतर दृष्टिकोण है।

लेकिन मुझे माइकल वेलेंटी के इस तरीके को नाम देने का सुझाव भी पसंद है कि MUST रिटर्न अशक्त होना चाहिए जैसे getEmployeeOrNull।

एक लेखक जो एक अपवाद को फेंकता है, डेवलपर के लिए ऑब्जेक्ट की वैधता का परीक्षण करने के लिए विकल्प को हटा रहा है, जो वस्तुओं के संग्रह पर बहुत खराब है, और डेवलपर को उनके उपभोग कोड को शाखा देते समय अपवाद से निपटने में मजबूर करता है।

एक डेवलपर वर्ग का उपभोग करने वाले के रूप में, मुझे आशा है कि लेखक मुझे अशक्त स्थिति से बचने या प्रोग्राम करने की क्षमता देता है जो उनके वर्ग / विधियों का सामना कर सकता है।

इसलिए एक डेवलपर के रूप में मैं एक विधि से NULL के खिलाफ रक्षात्मक कार्यक्रम करेगा। यदि लेखक ने मुझे एक अनुबंध दिया है जो हमेशा एक वस्तु देता है (NULL OBJECT हमेशा करता है) और उस वस्तु की एक विधि / संपत्ति होती है जिसके द्वारा वस्तु की वैधता का परीक्षण किया जाता है, तो मैं उस पद्धति / संपत्ति का उपयोग वस्तु को जारी रखने के लिए करूंगा। , अन्य वस्तु मान्य नहीं है और मैं इसका उपयोग नहीं कर सकता।

लब्बोलुआब यह है कि कक्षा / विधियों के लेखक को तंत्र प्रदान करना चाहिए जो एक डेवलपर अपनी रक्षात्मक प्रोग्रामिंग में उपयोग कर सकता है। यही है, विधि का एक स्पष्ट इरादा।

डेवलपर को हमेशा किसी अन्य वर्ग / विधि से लौटी वस्तुओं की वैधता का परीक्षण करने के लिए रक्षात्मक प्रोग्रामिंग का उपयोग करना चाहिए।

सादर

GregJF


0

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


0

एक जटिल कार्यक्रमों के विकास के दौरान अनपेक्षित नल कार्य उत्पन्न हो सकते हैं, और मृत कोड की तरह, इस तरह की घटनाएं प्रोग्राम संरचनाओं में गंभीर खामियों का संकेत देती हैं।

एक नल फ़ंक्शन या विधि का उपयोग अक्सर किसी ऑब्जेक्ट फ़्रेमवर्क में किसी revectorable फ़ंक्शन या ओवरराइड करने योग्य विधि के डिफ़ॉल्ट व्यवहार के रूप में किया जाता है।

Null_function @wikipedia


0

खैर, यह सुनिश्चित है कि विधि के उद्देश्य पर निर्भर करता है ... कभी-कभी, एक बेहतर विकल्प एक अपवाद फेंकना होगा। यह सब मामले से मामले पर निर्भर करता है।


0

यदि कोड कुछ इस तरह है:

command = get_something_to_do()

if command:  # if not Null
    command.execute()

यदि आपके पास एक डमी ऑब्जेक्ट है जिसका निष्पादन () विधि कुछ भी नहीं करती है, और आप इसे वापस करते हैं, तो उपयुक्त मामलों में नल के बजाय, आपको नल मामले की जांच करने की आवश्यकता नहीं है और इसके बजाय बस कर सकते हैं:

get_something_to_do().execute()

इसलिए, यहाँ समस्या NULL बनाम अपवाद की जाँच के बीच नहीं है, बल्कि इसके बजाय कॉलर के पास विशेष गैर-मामलों को अलग-अलग तरीके से (जो भी हो) या नहीं संभालना है।


0

मेरे उपयोग के मामले में मुझे विधि से एक मानचित्र वापस करने और फिर एक विशिष्ट कुंजी की तलाश करने की आवश्यकता थी। लेकिन अगर मैं एक खाली मानचित्र लौटाता हूं, तो यह NullPointerException को ले जाएगा और फिर यह खाली मानचित्र के बजाय बहुत अलग रिटर्निंग नल होगा। लेकिन जावा 8 से हम वैकल्पिक का उपयोग कर सकते हैं । ऊपर बहुत ही कारण है वैकल्पिक अवधारणा शुरू की गई थी।


-3

अच्छा दिन,

जब आप एक नई वस्तु बनाने में असमर्थ होते हैं तो NULL लौटाना कई API के लिए मानक अभ्यास है।

क्यों नरक यह बुरा डिजाइन है मुझे पता नहीं है।

संपादित करें: यह उन भाषाओं का सच है जहां आपके पास सी जैसे अपवाद नहीं हैं जहां यह कई वर्षों से सम्मेलन है।

HTH

'Avahappy,


2
यदि आप एक ऑब्जेक्ट बनाने में असमर्थ हैं, तो आपको वास्तव में एक अपवाद फेंकना चाहिए। यदि आप किसी ऐसे ऑब्जेक्ट को खोजने में असमर्थ हैं जो कुछ क्वेरी से मेल खाता है, तो अशक्त लौटने का रास्ता है।
थिलो

@ थिलो, मुझे दिखाओ कि सी में मुझे कैसे करना है और मुझे सबसे ज्यादा दिलचस्पी होगी।
रोब वेल्स

@ रॉब्ल्स सी एक ऑब्जेक्ट-ओरिएंटेड भाषा नहीं है, लेकिन इस सवाल को "ऊप" के रूप में टैग किया गया है
yegor256

@ yegor256 आप सही हैं। और मैं मूल OOP टैग से चूक गया। लेकिन, जैसा कि बीएस ने कहा कि सी ++ में एक क्लास सिर्फ कुछ अतिरिक्त सदस्य कार्यों के साथ एक संरचना है और कुछ फैंसी मेमोरी प्रबंधन आंतरिक रूप से हो रहा है। लेकिन अगर एक API को किसी स्ट्रक्चर को वापस करने के लिए सस्पेंड किया जाता है, तो जब आप स्ट्रक्चर नहीं बना सकते हैं तो NUL को वापस करना अक्सर कन्वेंशन होता है।
रोब वेल्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.