परहेज! = अशक्त कथन


4014

मैं object != nullबचने के लिए बहुत प्रयोग करता हूं NullPointerException

क्या इसका कोई अच्छा विकल्प है?

उदाहरण के लिए मैं अक्सर उपयोग करता हूं:

if (someobject != null) {
    someobject.doCalc();
}

यह उपरोक्त स्निपेट में ऑब्जेक्ट के NullPointerExceptionलिए जाँच करता है someobject

ध्यान दें कि स्वीकृत उत्तर पुराना हो सकता है, अधिक हाल ही के दृष्टिकोण के लिए https://stackoverflow.com/a/2386013/12943 देखें ।


120
@ शेरविन उत्साहवर्धक नल कोड को कम समझने योग्य और कम विश्वसनीय बनाता है।
टॉम हॉन्टिन -

44
एल्विस ऑपरेटरों को प्रस्तावित किया गया था लेकिन ऐसा लगता है कि यह जावा 7 में नहीं होगा । बहुत बुरा, ?। ?: और [?] अविश्वसनीय समय बचाने वाले हैं।
स्कॉट

72
नल का उपयोग नहीं करना यहां अन्य अधिकांश सुझावों से बेहतर है। अपवाद फेंकें, वापस न आएं या अशक्त न होने दें। BTW - 'assert' कीवर्ड बेकार है, क्योंकि यह डिफ़ॉल्ट रूप से अक्षम है। एक हमेशा-सक्षम विफलता तंत्र का उपयोग करें
ianpojman

13
यह एक कारण है कि मैं अब स्काला का उपयोग क्यों कर रहा हूं। स्काला में सब कुछ अशक्त नहीं है। यदि आप "कुछ भी नहीं" पास या वापस करने की अनुमति देना चाहते हैं, तो आपको केवल टी अलस तर्क या वापसी प्रकार के बजाय विकल्प [टी] का उपयोग करना होगा।
thekwasti

11
@thSoft वास्तव में, स्काला के भयानक Optionप्रकार को भाषा की अनिच्छा द्वारा नियंत्रित या अस्वीकार करने के लिए तैयार किया जाता है null। मैंने हैकरन्यूज़ पर इसका उल्लेख किया और नीचे उतर गया और बताया कि "स्कैला में कोई भी नल का उपयोग नहीं करता है"। लगता है कि, मैं पहले से ही सहकर्मी लिखित स्काला में नल ढूँढ रहा हूँ। हां, वे "इसे गलत कर रहे हैं" और इसके बारे में शिक्षित होना चाहिए, लेकिन तथ्य यह है कि भाषा का प्रकार सिस्टम मुझे इससे बचाए रखना चाहिए और यह नहीं करता है :(
एंड्रेस एफ

जवाबों:


2642

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

इसे दूसरे तरीके से रखने के लिए, दो उदाहरण हैं जहाँ अशक्त जाँच सामने आती है:

  1. जहां अनुबंध के संदर्भ में शून्य एक वैध प्रतिक्रिया है; तथा

  2. जहां यह एक वैध प्रतिक्रिया नहीं है।

(२) आसान है। या तो assertबयानों का उपयोग करें (दावे) या विफलता की अनुमति दें (उदाहरण के लिए, NullPointerException )। अभिक्रियाएँ एक अति-रेखांकित जावा सुविधा है जिसे 1.4 में जोड़ा गया था। वाक्य रचना है:

assert <condition>

या

assert <condition> : <object>

<condition>एक बूलियन अभिव्यक्ति कहां है और <object>एक ऐसी वस्तु है जिसके toString()विधि का आउटपुट त्रुटि में शामिल किया जाएगा।

एक assertबयान एक फेंकता है Error( AssertionError) अगर हालत सही नहीं है। डिफ़ॉल्ट रूप से, Java मुखरता को अनदेखा करता है। आप -eaJVM के विकल्प को पास करके दावे को सक्षम कर सकते हैं । आप अलग-अलग कक्षाओं और पैकेजों के लिए मुखरता को सक्षम और अक्षम कर सकते हैं। इसका मतलब है कि आप विकास और परीक्षण के दौरान अभिकथन के साथ कोड को मान्य कर सकते हैं, और उन्हें उत्पादन वातावरण में अक्षम कर सकते हैं, हालांकि मेरे परीक्षण ने जोर देने से कोई प्रदर्शन प्रभाव नहीं दिखाया है।

इस मामले में मुखरता का उपयोग नहीं करना ठीक है क्योंकि कोड बस विफल हो जाएगा, जो कि यदि आप अभिकथन का उपयोग करते हैं तो क्या होगा। एकमात्र अंतर यह है कि जोर के साथ यह जल्द ही हो सकता है, अधिक सार्थक तरीके से और संभवतः अतिरिक्त जानकारी के साथ, जो आपको यह पता लगाने में मदद कर सकता है कि ऐसा क्यों हुआ यदि आप इसकी उम्मीद नहीं कर रहे थे।

(१) थोड़ा कठिन है। यदि आपके पास उस कोड पर कोई नियंत्रण नहीं है जिसे आप कॉल कर रहे हैं तो आप अटक गए हैं। यदि नल एक वैध प्रतिक्रिया है, तो आपको इसके लिए जांच करनी होगी।

यदि यह कोड है जिसे आप नियंत्रित करते हैं, हालांकि (और यह अक्सर मामला होता है), तो यह एक अलग कहानी है। प्रतिक्रिया के रूप में नल का उपयोग करने से बचें। उन तरीकों से, जो संग्रह लौटाते हैं, यह आसान है: खाली संग्रह (या सरणियाँ) के बजाय नल के बजाय हर समय बहुत अधिक।

गैर-संग्रह के साथ यह कठिन हो सकता है। इसे एक उदाहरण के रूप में देखें: यदि आपके पास ये इंटरफेस हैं:

public interface Action {
  void doSomething();
}

public interface Parser {
  Action findAction(String userInput);
}

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

एक वैकल्पिक समाधान अशक्त कभी नहीं लौटना है और इसके बजाय अशक्त वस्तु पैटर्न का उपयोग करना है :

public class MyParser implements Parser {
  private static Action DO_NOTHING = new Action() {
    public void doSomething() { /* do nothing */ }
  };

  public Action findAction(String userInput) {
    // ...
    if ( /* we can't find any actions */ ) {
      return DO_NOTHING;
    }
  }
}

की तुलना करें:

Parser parser = ParserFactory.getParser();
if (parser == null) {
  // now what?
  // this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
  // do nothing
} else {
  action.doSomething();
}

सेवा

ParserFactory.getParser().findAction(someInput).doSomething();

जो एक बेहतर डिजाइन है क्योंकि यह अधिक संक्षिप्त कोड की ओर जाता है।

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

try {
    ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
    userConsole.err(anfe.getMessage());
}

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

public Action findAction(final String userInput) {
    /* Code to return requested Action if found */
    return new Action() {
        public void doSomething() {
            userConsole.err("Action not found: " + userInput);
        }
    }
}

631
मैं DO_NOTHING कार्रवाई के लिए आपके कथनों से असहमत हूं। यदि खोज क्रिया पद्धति कोई क्रिया नहीं ढूंढ पा रही है, तो वापस लौटना सही काम है। आपने अपने कोड में "पाया" एक क्रिया है जो वास्तव में नहीं मिली है, जो कि प्रयोग करने योग्य कार्रवाई खोजने के लिए विधि के सिद्धांत का उल्लंघन करती है।
MetroidFan2002

266
मैं मानता हूं कि जावा में विशेष रूप से सूचियों के साथ अशक्त है। बहुत सारे एप बेहतर होंगे यदि वे रिक्त सूची / सरणी / संग्रह को शून्य के बजाय वापस करते हैं। कई बार, नल का उपयोग किया जाता है जहां इसके बजाय एक अपवाद फेंक दिया जाना चाहिए। यदि पार्सर पार्स नहीं कर सकता है तो एक अपवाद को फेंक दिया जाना चाहिए।
लाप्ली एंडरसन

92
यहाँ बाद का उदाहरण है, IIRC, नल ऑब्जेक्ट डिज़ाइन पैटर्न।
स्टीवन एवर्स

62
@ कश (और MetroidFan2002)। सरल, कि अनुबंध में डाल दिया और फिर यह स्पष्ट है कि एक गैर-पाया गया रिटर्न कार्रवाई कुछ नहीं करेगा। यदि यह कॉल करने वाले के लिए महत्वपूर्ण जानकारी है, तो यह पता लगाने का एक तरीका प्रदान करें कि यह एक गैर-पाया जाने वाला कार्य था (अर्थात यदि परिणाम DO_NOTHING ऑब्जेक्ट था, तो यह जांचने के लिए एक विधि प्रदान करें)। वैकल्पिक रूप से, यदि कार्रवाई सामान्य रूप से पाई जानी चाहिए, तो आपको अभी भी अशक्त नहीं लौटना चाहिए, बल्कि विशेष रूप से उस स्थिति को इंगित करने वाले अपवाद को फेंकना चाहिए - इससे अभी भी बेहतर कोड होता है। यदि वांछित है, तो कार्रवाई करने के लिए जाँच करने के लिए एक अलग विधि वापस बुलियन प्रदान करें।
केविन ब्रॉक

35
संक्षिप्तता समान गुणवत्ता कोड नहीं है। मुझे खेद है कि आप ऐसा सोचते हैं। आपका कोड उन स्थितियों को छुपाता है जहां एक त्रुटि लाभप्रद होगी।
गशूगर

634

यदि आप JetBrains IntelliJ IDEA , Eclipse या Netbeans जैसे किसी जावा IDE का उपयोग करते हैं (या उपयोग करने की योजना बना रहे हैं) या फिर फाइबग्स जैसा कोई टूल है तो आप इस समस्या को हल करने के लिए एनोटेशन का उपयोग कर सकते हैं।

मूल रूप से, आप मिल गया है @Nullableऔर @NotNull

आप इस तरह विधि और मापदंडों में उपयोग कर सकते हैं:

@NotNull public static String helloWorld() {
    return "Hello World";
}

या

@Nullable public static String helloWorld() {
    return "Hello World";
}

दूसरा उदाहरण संकलन (IntelliJ IDEA में) नहीं होगा।

जब आप helloWorld()किसी दूसरे कोड में पहले फ़ंक्शन का उपयोग करते हैं :

public static void main(String[] args)
{
    String result = helloWorld();
    if(result != null) {
        System.out.println(result);
    }
}

अब IntelliJ IDEA कंपाइलर आपको बताएगा कि चेक बेकार है, क्योंकि helloWorld()फंक्शन nullकभी वापस नहीं आएगा ।

पैरामीटर का उपयोग करना

void someMethod(@NotNull someParameter) { }

अगर आप कुछ लिखते हैं:

someMethod(null);

यह संकलन नहीं होगा।

अंतिम उदाहरण का उपयोग करते हुए @Nullable

@Nullable iWantToDestroyEverything() { return null; }

यह कर रहा हूं

iWantToDestroyEverything().something();

और आप सुनिश्चित हो सकते हैं कि ऐसा नहीं होगा। :)

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

IntelliJ IDEA 10.5 और पर, उन्होंने किसी अन्य @Nullable @NotNullकार्यान्वयन के लिए समर्थन जोड़ा ।

ब्लॉग पोस्ट देखें अधिक लचीला और विन्यास योग्य @ Nullable / @ NotNull एनोटेशन


119
@NotNull, @Nullableऔर अन्य अशक्त एनोटेशन JSR 305 का हिस्सा हैं । आप FindBugs जैसे टूल के साथ संभावित समस्याओं का पता लगाने के लिए भी उनका उपयोग कर सकते हैं ।
जसक एस

32
मुझे यह अजीब अजीब लगता है कि @NotNull& @Nullableइंटरफेस पैकेज में रहते हैं com.sun.istack.internal। (मुझे लगता है कि मैं एक मालिकाना एपीआई का उपयोग करने के बारे में चेतावनियों के साथ com.sun जुड़ा हुआ हूं।)
जोनिक

20
कोड पोर्टेबिलिटी जेटब्राइंस के साथ शून्य हो जाती है। मैं विचार करने के लिए दो (वर्ग) स्तर तक विचार करूँगा। लेइक जसेक एस ने कहा कि वे किसी भी तरह से जेएसआर का हिस्सा हैं जो मुझे लगा कि जेएसआर303 है।
जावा का बेबी

10
मैं वास्तव में नहीं सोचता कि कस्टम कंपाइलर का उपयोग इस समस्या का एक व्यवहार्य समाधान है।
शिवन ड्रैगन

64
एनोटेशन के बारे में अच्छी बात, जो है @NotNullऔर @Nullableयह है कि वे अच्छी तरह से नीचा दिखाते हैं जब स्रोत कोड एक सिस्टम द्वारा बनाया जाता है जो उन्हें समझ में नहीं आता है। तो, वास्तव में, यह तर्क कि कोड पोर्टेबल नहीं है, अमान्य हो सकता है - यदि आप एक सिस्टम का उपयोग करते हैं जो इन एनोटेशन का समर्थन करता है और समझता है, तो आपको कड़ी त्रुटि जाँच का अतिरिक्त लाभ मिलता है, अन्यथा आपको इससे कम मिलता है लेकिन आपका कोड अभी भी होना चाहिए ठीक बनाएं, और आपके चलने वाले कार्यक्रम की गुणवत्ता THE SAME है, क्योंकि ये एनोटेशन वैसे भी रनटाइम पर लागू नहीं किए गए थे। इसके अलावा, सभी कंपाइलर कस्टम हैं ;-)
एमएन

321

यदि अशक्त-मूल्यों की अनुमति नहीं है

यदि आपकी विधि को बाहरी रूप से कहा जाता है, तो कुछ इस तरह से शुरू करें:

public void method(Object object) {
  if (object == null) {
    throw new IllegalArgumentException("...");
  }

फिर, उस विधि के बाकी हिस्सों में, आपको पता चल जाएगा कि objectयह अशक्त नहीं है।

यदि यह एक आंतरिक विधि है (एपीआई का हिस्सा नहीं है), तो बस दस्तावेज है कि यह शून्य नहीं हो सकता है, और यह बात है।

उदाहरण:

public String getFirst3Chars(String text) {
  return text.subString(0, 3);
}

हालाँकि, यदि आपकी विधि अभी मान को पास करती है, और अगली विधि इसे चालू करती है, तो यह समस्याग्रस्त हो सकता है। उस स्थिति में आप ऊपर दिए गए तर्क की जाँच कर सकते हैं।

यदि अशक्त है

यह वास्तव में निर्भर करता है। अगर पता चले कि मैं अक्सर कुछ ऐसा करता हूं:

if (object == null) {
  // something
} else {
  // something else
}

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


मेरे लिए मुहावरे का उपयोग करना वास्तव में दुर्लभ है " if (object != null && ..."।

यदि आप आमतौर पर मुहावरे का उपयोग करते हैं, तो आपको उदाहरणों को दिखाना आसान हो सकता है।


94
IllegalArgumentException को फेंकने में क्या बात है? मुझे लगता है कि NullPointerException क्लियर होगी, और अगर आप खुद को null-check नहीं करते हैं, तो इसे भी फेंक दिया जाएगा। मैं या तो जोर का प्रयोग करूँगा या कुछ भी नहीं।
एक्सल

23
यह संभावना नहीं है कि अशक्त की तुलना में हर दूसरे मूल्य स्वीकार्य हैं। आपके पास IllegalArgumentException, OutOfRageException आदि हो सकते हैं। कभी-कभी यह समझ में आता है। अन्य बार जब आप बहुत सारे अपवाद वर्गों का निर्माण करते हैं जो किसी भी मूल्य को नहीं जोड़ते हैं, तो आप बस IllegalArgumentException का उपयोग करते हैं। यह समझ में नहीं आता है कि अशक्त-इनपुट के लिए एक अपवाद है, और बाकी सब के लिए एक और एक है।
myplacedk

7
हां, मैं विफल-फास्ट-सिद्धांत के लिए सहमत हूं, लेकिन ऊपर दिए गए उदाहरण में, मान को पारित नहीं किया गया है, लेकिन वह वस्तु है जिस पर एक विधि कहा जाएगा। तो यह समान रूप से तेजी से विफल हो जाता है, और केवल एक अपवाद फेंकने के लिए एक अशक्त जांच को जोड़ना जो कि एक ही समय और स्थान पर वैसे भी फेंक दिए जाते हैं, किसी भी आसान डिबगिंग को नहीं लगता है।
एक्सल

8
एक सुरक्षा छेद? JDK इस तरह कोड से भरा है। यदि आप उपयोगकर्ता को स्टैकट्रैक्स नहीं देखना चाहते हैं, तो उन्हें अक्षम करें। किसी ने भी यह नहीं कहा कि व्यवहार का दस्तावेजीकरण नहीं किया गया है। MySQL में C लिखा जाता है जहाँ dereferencing नल पॉइंटर्स अपरिभाषित व्यवहार करते हैं, अपवाद को फेंकने जैसा कुछ भी नहीं है।
fgb

8
throw new IllegalArgumentException("object==null")
Thorbjørn रेवन एंडरसन

238

वाह, मुझे एक और जवाब जोड़ने से लगभग नफरत है जब हमारे पास सिफारिश करने के लिए 57 अलग-अलग तरीके हैं NullObject pattern, लेकिन मुझे लगता है कि इस सवाल में रुचि रखने वाले कुछ लोग यह जानना पसंद कर सकते हैं कि "null-safe" जोड़ने के लिए जावा 7 के लिए मेज पर एक प्रस्ताव है हैंडलिंग " -एक-समान-शून्य तर्क के लिए सुव्यवस्थित सिंटैक्स।

एलेक्स मिलर द्वारा दिया गया उदाहरण इस प्रकार है:

public String getPostcode(Person person) {  
  return person?.getAddress()?.getPostcode();  
}  

?.साधन केवल de-संदर्भ बाईं पहचानकर्ता अगर यह रिक्त नहीं है, अन्यथा रूप में अभिव्यक्ति के शेष का मूल्यांकन null। कुछ लोग, जैसे जावा पॉज़ सदस्य डिक वॉल और डेवोक्सक्स के मतदाता वास्तव में इस प्रस्ताव को पसंद करते हैं, लेकिन इस आधार पर भी विरोध है कि यह वास्तव nullमें एक प्रहरी मूल्य के रूप में अधिक उपयोग को प्रोत्साहित करेगा ।


अपडेट: जावा 7 में एक अशक्त ऑपरेटर के लिए एक आधिकारिक प्रस्ताव प्रोजेक्ट सिक्का के तहत प्रस्तुत किया गया है सिंटैक्स ऊपर दिए गए उदाहरण से थोड़ा अलग है, लेकिन यह एक ही धारणा है।


अद्यतन: अशक्त-सुरक्षित ऑपरेटर प्रस्ताव ने इसे प्रोजेक्ट कॉइन में नहीं बनाया। तो, आप इस वाक्यविन्यास को जावा 7 में नहीं देख पाएंगे।


20
मुझे लगता है कि यह गलत है। यह निर्दिष्ट करने का एक तरीका होना चाहिए कि किसी दिए गए चर को ALWAYS गैर-शून्य है।
थोरबजोर्न रेवन एंडरसन

5
अपडेट: प्रस्ताव Java7 नहीं करेगा। ब्लॉग्स देखें । www.sarcy/entry/project_coin_final_five
बोरिस टेरिक

9
दिलचस्प विचार लेकिन वाक्य रचना का विकल्प बेतुका है; मैं नहीं चाहता कि प्रत्येक संयुक्त में प्रश्नवाचक चिह्न से भरा कोडबेस हो।
रॉब

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

8
यह मैंने देखा है सबसे सरल विचार है। इसे C सिंटैक्स की प्रत्येक समझदार भाषा में जोड़ा जाना चाहिए। मैं "पिन क्वेश्चन मार्क्स" के बजाय हर दिन स्क्रैच ऑफ़ लाइन्स के माध्यम से या पूरे दिन "गार्ड क्लॉस" के माध्यम से चाहता हूँ।
विक्टर

196

यदि अपरिभाषित मानों की अनुमति नहीं है:

संभावित null dereferencing के बारे में आपको सूचित करने के लिए आप अपनी IDE कॉन्फ़िगर कर सकते हैं। जैसे ग्रहण में, प्राथमिकताएँ देखें > जावा> संकलक> त्रुटियां / चेतावनी / अशक्त विश्लेषण

यदि अपरिभाषित मानों की अनुमति है:

यदि आप एक नए एपीआई को परिभाषित करना चाहते हैं जहां अपरिभाषित मूल्य समझ में आते हैं , तो विकल्प पैटर्न का उपयोग करें (कार्यात्मक भाषाओं से परिचित हो सकते हैं)। इसके निम्नलिखित फायदे हैं:

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

जावा 8 में एक अंतर्निहित Optionalवर्ग (अनुशंसित) है; पुराने संस्करणों के लिए, वहाँ, पुस्तकालय विकल्प हैं, उदाहरण के लिए अमरूद की Optionalया FunctionalJava की Option। लेकिन कई कार्यात्मक-शैली के पैटर्न की तरह, जावा (यहां तक ​​कि 8) में विकल्प का उपयोग करने से कुछ बॉयलरप्लेट में परिणाम होता है, जिसे आप कम वर्बोज़ जेवीएम भाषा, जैसे स्काला या एक्सएक्सएंड का उपयोग करके कम कर सकते हैं।

यदि आपको एक एपीआई से निपटना पड़ता है जो नल वापस कर सकता है , तो आप जावा में बहुत कुछ नहीं कर सकते। Xtend और Groovy के पास एल्विस ऑपरेटर ?: और नल-सुरक्षित डेरेफेरेंस ऑपरेटर हैं ?. , लेकिन ध्यान दें कि यह अशक्त संदर्भ के मामले में शून्य देता है, इसलिए यह नल की उचित हैंडलिंग को "ख़राब" करता है।


22
दरअसल, ऑप्शन पैटर्न कमाल का है। कुछ जावा समकक्ष मौजूद हैं। अमरूद में वैकल्पिक नाम का एक सीमित संस्करण होता है जो अधिकांश कार्यात्मक सामान को छोड़ देता है। हास्केल में, इस पैटर्न को शायद कहा जाता है।
बेन हार्डी

9
एक वैकल्पिक कक्षा जावा 8 में उपलब्ध होगी
पियरे हेनरी

1
... और यह (अभी तक) के पास न तो मैप है और न ही फ्लैट मैप: download.java.net/jdk8/docs/api/java/util/Optional.html
thSoft

3
वैकल्पिक पैटर्न कुछ भी हल नहीं करता है; एक संभावित अशक्त वस्तु के बजाय, अब आपके पास दो हैं।
Boann

1
@ बोआन, अगर देखभाल के साथ उपयोग किया जाता है, तो आप अपनी सभी NPEs समस्या को हल करते हैं। यदि नहीं, तो मुझे लगता है कि एक "उपयोग" समस्या है।
लुई एफ।

189

केवल इस स्थिति के लिए -

यह जाँचना कि क्या चर बराबर विधि लागू करने से पहले एक शून्य है (नीचे एक स्ट्रिंग उदाहरण की तुलना करें):

if ( foo.equals("bar") ) {
 // ...
}

NullPointerExceptionयदि fooमौजूद नहीं है तो परिणाम होगा ।

आप Stringइस तरह से अपने एस की तुलना कर सकते हैं :

if ( "bar".equals(foo) ) {
 // ...
}

42
मैं सहमत हूँ - केवल उस स्थिति में। मैं प्रोग्रामर्स को खड़ा नहीं कर सकता जो इसे अगले अनावश्यक स्तर पर ले गए हैं और लिखते हैं कि क्या (null! = MyVar) ... बस मुझे बदसूरत लगता है और कोई उद्देश्य नहीं है!
एलेक्स वर्डेन

20
यह एक विशेष उदाहरण है, शायद सबसे अच्छा प्रयोग, एक सामान्य अच्छे अभ्यास का: यदि आप इसे जानते हैं, तो हमेशा करते हैं <object that you know that is not null>.equals(<object that might be null>);। यह अन्य तरीकों के अलावा काम करता है, equalsयदि आप अनुबंध जानते हैं और उन विधियों के nullमापदंडों को संभाल सकते हैं ।
स्टेफ

9
यह पहला उदाहरण है जो मैंने योदा स्थितियों के बारे में देखा है जो वास्तव में समझ में आता है
एरिन ड्रमंड

6
NullPointerException को एक कारण से फेंक दिया जाता है। उन्हें फेंक दिया जाता है क्योंकि एक वस्तु अशक्त है जहां यह नहीं होना चाहिए। यह इस FIX करने के लिए प्रोग्रामर का काम है, समस्या को छिपाएं नहीं।
ओलिवर वाटकिंस

1
ट्राइ-कैच-डूइंगिंग समस्या को छुपाता है, यह भाषा में गायब चीनी के आसपास काम करने के लिए एक वैध अभ्यास है।
इकोक्स

167

जावा 8 के साथ नया java.util.Optionalवर्ग आता है जो यकीनन कुछ समस्या को हल करता है। कम से कम यह कह सकते हैं कि यह कोड की पठनीयता में सुधार करता है, और सार्वजनिक एपीआई के मामले में क्लाइंट डेवलपर के लिए एपीआई के अनुबंध को स्पष्ट कर देता है।

वे इस तरह काम करते हैं:

किसी दिए गए प्रकार ( Fruit) के लिए एक वैकल्पिक ऑब्जेक्ट एक विधि के रिटर्न प्रकार के रूप में बनाया गया है। यह खाली हो सकता है या इसमें कोई Fruitवस्तु हो सकती है:

public static Optional<Fruit> find(String name, List<Fruit> fruits) {
   for (Fruit fruit : fruits) {
      if (fruit.getName().equals(name)) {
         return Optional.of(fruit);
      }
   }
   return Optional.empty();
}

अब इस कोड को देखें, जहां हम दिए गए फलों के उदाहरण के लिए Fruit( fruits) की एक सूची खोजते हैं :

Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
   Fruit fruit = found.get();
   String name = fruit.getName();
}

आप map()एक वैकल्पिक ऑब्जेक्ट पर एक संगणना प्रदर्शन करने या उससे मूल्य निकालने के लिए ऑपरेटर का उपयोग कर सकते हैं । orElse()आप लापता मूल्यों के लिए एक वापसी प्रदान करते हैं।

String nameOrNull = find("lemon", fruits)
    .map(f -> f.getName())
    .orElse("empty-name");

बेशक, अशक्त / खाली मूल्य के लिए चेक अभी भी आवश्यक है, लेकिन कम से कम डेवलपर को सचेत है कि मूल्य खाली हो सकता है और चेक को भूलने का जोखिम सीमित है।

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

बेशक Optionalएक विधि तर्क के रूप में भी इस्तेमाल किया जा सकता है, शायद कुछ मामलों में 5 या 10 ओवरलोडिंग विधियों की तुलना में वैकल्पिक तर्कों को इंगित करने का एक बेहतर तरीका।

Optionalअन्य सुविधाजनक तरीके प्रदान करता है, जैसे orElseकि डिफ़ॉल्ट मान का उपयोग करने की अनुमति देता है, और ifPresentयह लंबोदर भाव के साथ काम करता है ।

मैं आपको इस लेख (इस उत्तर को लिखने के लिए मेरा मुख्य स्रोत) को पढ़ने के लिए आमंत्रित करता हूं जिसमें NullPointerException(और सामान्य अशक्त सूचक में) समस्याग्रस्त होने के साथ-साथ (आंशिक) समाधान Optionalभी अच्छी तरह से समझाया गया है: जावा वैकल्पिक ऑब्जेक्ट


11
Google के अमरूद में जावा 6+ के लिए एक वैकल्पिक निहितार्थ है।
ब्रैडली गॉटफ्रीड

13
यह ज़ोर देना बहुत ज़रूरी है कि वैकल्पिक का उपयोग केवल ifresent () के साथ करने पर सामान्य नल जाँच से अधिक मूल्य नहीं जुड़ता है । यह मुख्य मूल्य है कि यह एक ऐसा सन्यासी है जिसका उपयोग मानचित्र / फ्लैपपून के फंक्शन चेन में किया जा सकता है, जो कि ग्रूवी में एल्विस ऑपरेटर के समान परिणाम प्राप्त करता है। इस उपयोग के बिना भी, हालांकि, मुझे orElse / orElseThrow सिंटैक्स भी बहुत उपयोगी लगता है।
कॉर्नेल मैसन

इस ब्लॉग पर ऑप्शनल विंटरबे.बीपोस्ट्स २०५
२०१५/

4
क्यों लोगों ऐसा करने के लिए प्रवृत्ति है if(optional.isPresent()){ optional.get(); }के बजायoptional.ifPresent(o -> { ...})
सत्येंद्र कुमार

1
इसलिए, एपीआई संविदात्मक संकेतों के अलावा, यह वास्तव में कार्यात्मक प्रोग्रामर के खानपान के बारे में है जो पूरी तरह से तरीकों का आनंद लेते हैं।
क्रश करें

125

इस बात पर निर्भर करता है कि आप किस प्रकार की वस्तुओं की जाँच कर रहे हैं, आप अपाचे कॉमन्स में कुछ वर्गों का उपयोग करने में सक्षम हो सकते हैं जैसे: अपाचे कॉमन्स लैंग और अपाचे कॉमन्स संग्रह

उदाहरण:

String foo;
...
if( StringUtils.isBlank( foo ) ) {
   ///do something
}

या (आप की जाँच करने की आवश्यकता पर निर्भर करता है):

String foo;
...
if( StringUtils.isEmpty( foo ) ) {
   ///do something
}

StringUtils वर्ग केवल कई में से एक है; कॉमन्स में काफी अच्छे वर्ग हैं जो सुरक्षित हेरफेर करते हैं।

यहाँ एक उदाहरण दिया गया है कि जब आप अपाचे पुस्तकालय (कॉमन्स-लैंग-2.4.जर) को शामिल करते हैं तो आप जेएवीए में शून्य विलोपन का उपयोग कैसे कर सकते हैं

public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) {
    Validate.notNull(validationEventHandler,"ValidationHandler not Injected");
    return read(new StringReader(xml), true, validationEventHandler);
}

और यदि आप स्प्रिंग का उपयोग कर रहे हैं, तो स्प्रिंग के पैकेज में भी समान कार्यक्षमता है, लाइब्रेरी देखें (स्प्रिंग-2.4.6.jar)

वसंत से इस स्थिर वर्ग का उपयोग कैसे करें पर उदाहरण (org.springframework.util.Assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");

5
इसके अलावा, आप अपाचे कॉमन्स से अधिक सामान्य संस्करण का उपयोग कर सकते हैं, जो कि मेरे द्वारा खोजे गए पैराम की जांच करने के तरीकों की शुरुआत में काफी उपयोगी हैं। Validate.notNull (ऑब्जेक्ट, "ऑब्जेक्ट शून्य नहीं होना चाहिए"); commons.apache.org/lang/apidocs/org/apache/commons/lang/…
monojohnny

@monojohnny में मुखर बयानों का उपयोग मान्य है? मैं पूछता हूं कि क्योंकि JVM पर Assert सक्रिय / निष्क्रिय हो सकता है और यह सुझाव है कि उत्पादन में उपयोग न करें।
कुरापिका 16

ऐसा मत सोचो - मेरा मानना ​​है कि अगर मान्यता विफल हो जाती है तो यह सिर्फ एक
रनटाइम एक्सप्रेशन

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

आपको ऑब्जेक्ट के लिए जांच करना होगा! = नल तभी होगा जब आप उस मामले को संभालना चाहते हैं जहां ऑब्जेक्ट अशक्त हो सकता है ...

Null / notnull params: http://tech.puredanger.com/java7/#jsr308 के साथ मदद करने के लिए Java7 में नई एनोटेशन जोड़ने का प्रस्ताव है



91

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


2
जोर का उपयोग करने के लिए बेहतर है, यानी अनुबंध। नॉटनॉल (एबीसी, "एबीसी गैर-अशक्त होना चाहिए, क्या यह xyz के दौरान लोड करने में विफल रहा?"); - यह अगर (abc! = null) करने से ज्यादा कॉम्पैक्ट तरीका है {नया
RuntimeException

76

Google संग्रह ढांचा अशक्त जाँच को प्राप्त करने के लिए एक अच्छा और सुरुचिपूर्ण तरीका प्रदान करता है।

इस तरह से एक पुस्तकालय वर्ग में एक विधि है:

static <T> T checkNotNull(T e) {
   if (e == null) {
      throw new NullPointerException();
   }
   return e;
}

और उपयोग है (साथ import static):

...
void foo(int a, Person p) {
   if (checkNotNull(p).getAge() > a) {
      ...
   }
   else {
      ...
   }
}
...

या आपके उदाहरण में:

checkNotNull(someobject).doCalc();

71
एमएमएम, क्या अंतर है? p.getAge () कम ओवरहेड और एक स्पष्ट स्टैक ट्रेस के साथ एक ही एनपीई को फेंक देगा। मैं क्या खो रहा हूँ?
मायसोमिक

15
अपने उदाहरण में IllegalArgumentException ("e == null") को फेंकना बेहतर है क्योंकि यह स्पष्ट रूप से इंगित करता है कि यह एक प्रोग्रामर-इच्छित अपवाद है (समस्या की पहचान करने के लिए पर्याप्त जानकारी के साथ वास्तव में अनुचर को अनुमति देने के लिए)। NullPointerException को JVM के लिए आरक्षित किया जाना चाहिए, क्योंकि यह तब स्पष्ट रूप से इंगित करता है कि यह अनजाने में था (और आमतौर पर पहचान करने के लिए कहीं कठिन होता है)
Thorbjørn Ravn Andersen

6
यह अब Google अमरूद का हिस्सा है।
स्टीवन बेनिट्ज

32
मेरे लिए ओवर-इंजीनियरिंग जैसी खुशबू आ रही है। बस JVM को एक NPE फेंक दें और इस जंक के साथ अपने कोड को अव्यवस्थित न करें।
एलेक्स वर्डेन

5
मुझे यह पसंद है और तर्कों पर स्पष्ट जाँच के साथ अधिकांश तरीके और निर्माणकर्ता खोलते हैं; यदि कोई त्रुटि है, तो विधियाँ हमेशा पहली कुछ पंक्तियों पर विफल हो जाती हैं और मुझे कुछ पता चले बिना अपमानजनक संदर्भ पता चलता हैgetThing().getItsThing().getOtherThing().wowEncapsulationIsBroken().setLol("hi");
Cory Kendall

75

कभी-कभी, आपके पास ऐसे तरीके होते हैं जो इसके मापदंडों पर काम करते हैं जो एक सममित ऑपरेशन को परिभाषित करते हैं:

a.f(b); <-> b.f(a);

यदि आप जानते हैं कि बी कभी भी अशक्त नहीं हो सकता है, तो आप इसे स्वैप कर सकते हैं। यह बराबरी के लिए सबसे उपयोगी है: बजाय foo.equals("bar");बेहतर करने के "bar".equals(foo);


2
लेकिन तब आपको यह मान लेना होगा equals(कोई भी तरीका हो सकता है) अशक्त रूप से सही ढंग से निपटेगा। वास्तव में यह सब कर रहा है किसी और (या किसी अन्य विधि) को जिम्मेदारी दे रहा है।
सुपर जूसी

4
@Supericy मूल रूप से हाँ, लेकिन equals(या जो भी तरीका है) nullवैसे भी जांचना है। या स्पष्ट रूप से बताएं कि यह नहीं है।
एंजेलो फुच्स

74

नल ऑब्जेक्ट पैटर्न के बजाय - जिसके उपयोग हैं - आप उन स्थितियों पर विचार कर सकते हैं जहां नल ऑब्जेक्ट बग है।

जब अपवाद फेंक दिया जाता है, तो स्टैक ट्रेस की जांच करें और बग के माध्यम से काम करें।


17
समस्या यह है कि आमतौर पर आप संदर्भ ढीला करते हैं क्योंकि NullPointerException इंगित नहीं करता है कि कौन सा चर शून्य था, और आपके पास कई "" हैं - लाइन पर संचालन। "If (foo == null)" का उपयोग करके नई RuntimeException ("foo == null") को फेंकने के लिए आपको "स्पष्ट रूप से बताने की अनुमति मिलती है कि क्या गलत था, अपने ढेर का पता लगाने वालों को इसे ठीक करने के लिए बहुत अधिक मूल्य देते हैं।
थोरबजर्न रेवन एंडरसन

1
एंडरसन के साथ - मैं जावा के अपवाद प्रणाली को पसंद करूंगा जिसमें एक चर का नाम शामिल किया जा सके, जिस पर काम किया जा रहा है, ताकि NullPointerException न केवल उस रेखा को इंगित करे जो अपवाद घटित हुआ है, बल्कि चर नाम भी है। यह अपुष्ट सॉफ़्टवेयर में ठीक काम करना चाहिए।
fwielstra

मैं इसे बस अभी तक काम कर पाने में कामयाब रहे नहीं किया है, लेकिन यह वास्तव में इस समस्या का समाधान करने का इरादा है।
MatrixFrog

समस्या क्या है? बस उपयुक्त स्तर पर एनपीई को पकड़ें जहां पर्याप्त संदर्भ उपलब्ध है, संदर्भ जानकारी को डंप करें और अपवाद को फिर से डालें ... यह जावा के साथ इतना आसान है।
user1050755

3
मेरे पास एक प्रोफेसर था जो पद्धति कॉलिंग के खिलाफ प्रचार करता था। उनका सिद्धांत था कि आपको उन कॉल श्रृंखलाओं से सावधान रहना चाहिए जो 2 तरीकों से अधिक लंबी थीं। मुझे नहीं पता कि यह एक कठिन नियम है, लेकिन यह निश्चित रूप से एनपीई स्टैक निशान के साथ अधिकांश समस्याओं को दूर करता है।
RustyTheBoyRobot

74

नल कोई 'समस्या' नहीं है। यह एक पूर्ण मॉडलिंग टूल सेट का एक अभिन्न हिस्सा है । सॉफ्टवेयर का उद्देश्य दुनिया की जटिलता का मॉडल बनाना है और अशक्तता का बोझ उठाना है। नल जावा और इस तरह 'कोई डेटा' या 'अज्ञात' इंगित नहीं करता है । इसलिए इन उद्देश्यों के लिए नल का उपयोग करना उचित है। मैं 'अशक्त वस्तु' पैटर्न पसंद नहीं करता; मुझे लगता है कि यह ' अभिभावकों की समस्या को दूर करेगा '।
यदि आप मुझसे पूछें कि मेरी प्रेमिका का नाम क्या है तो मैं आपको बताऊंगा कि मेरी कोई प्रेमिका नहीं है। जावा भाषा में मैं अशक्त लौटूंगा। एक विकल्प कुछ समस्या को इंगित करने के लिए सार्थक अपवाद को फेंकना होगा जो (या डॉन) नहीं हो सकता

  1. एक 'अज्ञात प्रश्न' के लिए 'अज्ञात उत्तर' दें। (जहां यह व्यापार के दृष्टिकोण से सही है, अशक्त रहें) उपयोग करने से पहले एक बार एक विधि के अंदर अशक्त के लिए तर्कों की जाँच करना, कॉल करने से पहले उन्हें जाँचने से कई कॉलर्स को राहत देता है।

    public Photo getPhotoOfThePerson(Person person) {
        if (person == null)
            return null;
        // Grabbing some resources or intensive calculation
        // using person object anyhow.
    }

    पिछली मेरी फोटो लाइब्रेरी से गैर-मौजूद प्रेमिका की कोई तस्वीर नहीं पाने के लिए सामान्य तर्क प्रवाह की ओर जाता है।

    getPhotoOfThePerson(me.getGirlfriend())

    और यह नए आने वाले जावा एपीआई (आगे की ओर) के साथ फिट बैठता है

    getPhotoByName(me.getGirlfriend()?.getName())

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

    public static MyEnum parseMyEnum(String value); // throws IllegalArgumentException
    public static MyEnum parseMyEnumOrNull(String value);

    और टाइप करने के लिए घृणा न करें <alt> + <shift> + <j>(ग्रहण में जेवाडॉक उत्पन्न करें) और आपके लिए सार्वजनिक एपीआई के लिए तीन अतिरिक्त शब्द लिखें। यह सभी के लिए पर्याप्त से अधिक होगा, लेकिन जो लोग प्रलेखन नहीं पढ़ते हैं।

    /**
     * @return photo or null
     */

    या

    /**
     * @return photo, never null
     */
  2. यह बल्कि सैद्धांतिक मामला है और ज्यादातर मामलों में आपको जावा नाल सुरक्षित एपीआई (यदि यह एक और 10 वर्षों में जारी किया जाएगा) पसंद करना चाहिए, लेकिन NullPointerExceptionएक का उपवर्ग है Exceptionइस प्रकार यह एक रूप है Throwableजो उन स्थितियों को इंगित करता है जो एक उचित अनुप्रयोग को पकड़ना चाहते हैं ( जावदोक )! अपवादों के पहले सबसे अधिक लाभ और 'नियमित' कोड से अलग त्रुटि-हैंडलिंग कोड का उपयोग करने के लिए ( जावा के रचनाकारों के अनुसार ) यह उपयुक्त है, मेरे लिए, पकड़ने के लिए NullPointerException

    public Photo getGirlfriendPhoto() {
        try {
            return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName());
        } catch (NullPointerException e) {
            return null;
        }
    }

    सवाल उठ सकते हैं:

    प्र। यदि getPhotoDataSource()रिटर्न शून्य है तो क्या होगा ?
    A. यह बिजनेस लॉजिक पर निर्भर है। अगर मैं एक फोटो एल्बम खोजने में विफल रहता हूं तो मैं आपको कोई फोटो नहीं दिखाऊंगा। क्या होगा अगर appontext को इनिशियलाइज़ न किया जाए? इस पद्धति का व्यावसायिक तर्क इसके साथ है। यदि एक ही तर्क अधिक सख्त होना चाहिए तो एक अपवाद फेंकना यह व्यापार तर्क का हिस्सा है और अशक्त के लिए स्पष्ट जांच का उपयोग किया जाना चाहिए (केस 3)। बेहतर यहाँ नया जावा अशक्त-सुरक्षित एपीआई फिट निर्दिष्ट करने के लिए चुनिंदा क्या तात्पर्य है और क्या संकेत नहीं करता प्रारंभ करने के लिए असफल फास्ट प्रोग्रामर त्रुटि के मामले में किया जाना है।

    Q. अनावश्यक कोड को निष्पादित किया जा सकता है और अनावश्यक संसाधनों को पकड़ा जा सकता है।
    A. ऐसा हो सकता है अगर getPhotoByName()डेटाबेस कनेक्शन को खोलने की कोशिश करें, PreparedStatementऔर उस व्यक्ति के नाम को SQL पैरामीटर के रूप में अंतिम रूप से उपयोग करें। अज्ञात प्रश्न के लिए दृष्टिकोण एक अज्ञात उत्तर देता है (केस 1) यहां काम करता है। संसाधनों को हथियाने से पहले विधि को मापदंडों की जांच करनी चाहिए और यदि आवश्यक हो तो 'अज्ञात' परिणाम लौटाएं।

    Q. ट्राई क्लोजर ओपनिंग के कारण इस एप्रोच में पेनल्टी है।
    A. सॉफ्टवेयर को पहले समझना और संशोधित करना आसान होना चाहिए। इसके बाद ही, कोई प्रदर्शन के बारे में सोच सकता है, और यदि आवश्यक हो तो ही! और जहां जरूरत हो! ( स्रोत ), और कई अन्य)।

    पुनश्च। यह दृष्टिकोण "नियमित" कोड सिद्धांत से अलग त्रुटि-हैंडलिंग कोड के रूप में उपयोग करने के लिए उचित होगा, कुछ जगह पर उपयोग करने के लिए उचित है। अगले उदाहरण पर विचार करें:

    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        try {
            Result1 result1 = performSomeCalculation(predicate);
            Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
            Result3 result3 = performThirdCalculation(result2.getSomeProperty());
            Result4 result4 = performLastCalculation(result3.getSomeProperty());
            return result4.getSomeProperty();
        } catch (NullPointerException e) {
            return null;
        }
    }
    
    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        SomeValue result = null;
        if (predicate != null) {
            Result1 result1 = performSomeCalculation(predicate);
            if (result1 != null && result1.getSomeProperty() != null) {
                Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
                if (result2 != null && result2.getSomeProperty() != null) {
                    Result3 result3 = performThirdCalculation(result2.getSomeProperty());
                    if (result3 != null && result3.getSomeProperty() != null) {
                        Result4 result4 = performLastCalculation(result3.getSomeProperty());
                        if (result4 != null) {
                            result = result4.getSomeProperty();
                        }
                    }
                }
            }
        }
        return result;
    }

    पी पी एस। उपवास करने वालों के लिए (और प्रलेखन पढ़ने के लिए इतनी जल्दी नहीं) मैं यह कहना चाहूंगा कि मैंने अपने जीवन में कभी भी अशक्त-सूचक अपवाद (एनपीई) नहीं पकड़ा है। लेकिन यह संभावना जानबूझकर जावा रचनाकारों द्वारा डिजाइन की गई थी क्योंकि एनपीई एक उपवर्ग है Exception। हमारे पास जावा इतिहास में एक मिसाल है जब ThreadDeathऐसा Errorनहीं है क्योंकि यह वास्तव में एक एप्लिकेशन त्रुटि है, लेकिन पूरी तरह से क्योंकि इसे पकड़ने का इरादा नहीं था! एनपीई कितना फिट बैठता Errorहै ThreadDeath! लेकिन यह नहीं है।

  3. केवल 'डेटा' के लिए जाँच करें यदि व्यावसायिक तर्क का अर्थ है।

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person != null) {
            person.setPhoneNumber(phoneNumber);
            dataSource.updatePerson(person);
        } else {
            Person = new Person(personId);
            person.setPhoneNumber(phoneNumber);
            dataSource.insertPerson(person);
        }
    }

    तथा

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person == null)
            throw new SomeReasonableUserException("What are you thinking about ???");
        person.setPhoneNumber(phoneNumber);
        dataSource.updatePerson(person);
    }

    यदि AppContext या dataSource आरंभिक अनहेल्ड रनटाइम नहीं है, तो NullPointerException थ्रेड को चालू करेगा और थ्रेड. defaultUncaughtExceptionHandler द्वारा संसाधित किया जाएगा (आपके पसंदीदा लकड़हारे या अन्य सूचना मैकेनिज़्म को परिभाषित करने और उपयोग करने के लिए)। यदि सेट नहीं किया गया है, तो थ्रेडग्रुप # बिना किसी अपवाद के स्टैकट्रेस को सिस्टम में इरेट करेगा। एक को अनुप्रयोग त्रुटि लॉग की निगरानी करनी चाहिए और प्रत्येक अखंडित अपवाद के लिए जीरा मुद्दे को खोलना चाहिए जो वास्तव में अनुप्रयोग त्रुटि है। प्रोग्रामर को आरंभीकरण सामान में कहीं न कहीं बग को ठीक करना चाहिए।


6
पकड़ना NullPointerExceptionऔर लौटना nullडिबग के लिए भयानक है। आप वैसे भी बाद में एनपीई के साथ समाप्त होते हैं, और यह पता लगाना वास्तव में कठिन है कि मूल रूप से क्या अशक्त था।
आर्टब्रिस्टल

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

2
"शायद <टी> या वैकल्पिक <टी>" के रूप में आपको अभी भी कोड लिखने की आवश्यकता है जैसे if (maybeNull.hasValue()) {...}कि अंतर क्या है if (maybeNull != null)) {...}?
मैखायलो एडमोविक

1
"NullPointerException को पकड़ने और अशक्त लौटने के रूप में, डीबग करने के लिए भयानक है। आप एनपीई के साथ बाद में वैसे भी समाप्त हो जाते हैं, और यह पता लगाना वास्तव में कठिन है कि मूल रूप से अशक्त था"। मैं पूरी तरह से सहमत हूँ! उन मामलों में आपको एक दर्जन cases यदि ’स्टेटमेंट लिखना चाहिए या एनपीई को फेंक देना चाहिए यदि व्यावसायिक तर्क में डेटा की जगह है, या नए जावा से अशक्त सुरक्षित ऑपरेटर का उपयोग करें। लेकिन ऐसे मामले हैं जब मुझे इस बात की परवाह नहीं है कि सटीक कदम मुझे क्या अशक्त करते हैं। उदाहरण के लिए, स्क्रीन पर दिखाने से पहले उपयोगकर्ता के लिए कुछ मूल्यों की गणना जब आप उम्मीद करते हैं कि डेटा गायब हो सकता है।
मीकायलो एडमोविक

3
@MykhayloAdamovych: लाभ Maybe<T>या Optional<T>उस मामले में नहीं है जहां आपका Tअशक्त हो सकता है, लेकिन उस मामले में जहां इसे कभी अशक्त नहीं होना चाहिए। यदि आपके पास एक प्रकार है जिसका स्पष्ट रूप से अर्थ है "यह मान शून्य हो सकता है - सावधानी के साथ उपयोग करें", और आप इस प्रकार का उपयोग करते हैं और लगातार वापस आते हैं, तो जब भी आप Tअपने कोड में एक सादे पुराने देखते हैं , तो आप मान सकते हैं कि यह कभी भी अशक्त नहीं है। (पाठ्यक्रम, यह एक बहुत अधिक उपयोगी होगा यदि संकलक द्वारा प्रवर्तनीय हो।)
cHao

71

जावा 7 में एक नई java.util.Objectsउपयोगिता वर्ग है जिस पर एक requireNonNull()विधि है। यह सब करता है NullPointerExceptionयदि इसका तर्क शून्य है, तो इसे फेंक दिया जाता है, लेकिन यह कोड को थोड़ा साफ करता है। उदाहरण:

Objects.requireNonNull(someObject);
someObject.doCalc();

एक रचनाकार में असाइनमेंट से ठीक पहले जांचने के लिए यह विधि सबसे उपयोगी है , जहां इसका प्रत्येक उपयोग कोड की तीन पंक्तियों को बचा सकता है:

Parent(Child child) {
   if (child == null) {
      throw new NullPointerException("child");
   }
   this.child = child;
}

हो जाता है

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}

9
वास्तव में, आपका उदाहरण कोड ब्लोट का गठन करता है: पहली पंक्ति अतिसुधार है क्योंकि एनपीई को दूसरी पंक्ति में फेंक दिया जाएगा। ;-)
user1050755

1
सच। एक बेहतर उदाहरण होगा यदि दूसरी पंक्ति थी doCalc(someObject)
स्टुअर्ट मार्क्स

निर्भर करता है। यदि आप doCalc () के लेखक हैं, तो मैं उस विधि की बॉडी (यदि संभव हो) में चेक डालने का सुझाव दूंगा। और फिर आप सबसे अधिक संभावना है कि कुछObject.someMethod () कॉल करेंगे जहां फिर से अशक्त के लिए जाँच करने की कोई आवश्यकता नहीं है। :-)
उपयोगकर्ता १०५० --५५ '

ठीक है, अगर आप के लेखक नहीं हैं doCalc(), और यह NPE को तुरंत नहीं दिया जाता है, जब आपको null दिया जाता है, तो आपको null की जांच करने और खुद NPE को फेंकने की आवश्यकता होगी। इसके Objects.requireNonNull()लिए जो है।
स्टुअर्ट मार्क्स

7
यह सिर्फ कोड ब्लोट नहीं है। एक विधि के माध्यम से आधे रास्ते से आगे की जांच करने के लिए बेहतर है जो साइड इफेक्ट्स का कारण बनता है या समय / स्थान का उपयोग करता है।
रोब ग्रांट

51

अंततः, एक अलग प्रोग्रामिंग भाषा का उपयोग करके इस समस्या को पूरी तरह से हल करने का एकमात्र तरीका है:

  • ऑब्जेक्टिव-सी में, आप एक विधि को लागू करने के बराबर कर सकते हैं nil, और बिल्कुल कुछ भी नहीं होगा। यह अधिकांश अशक्त जांचों को अनावश्यक बनाता है, लेकिन यह निदान करने में त्रुटियों को बहुत कठिन बना सकता है।
  • में अच्छा एक संभावित-अशक्त संस्करण और एक नहीं अशक्त संस्करण:, एक जावा व्युत्पन्न भाषा, वहाँ सभी प्रकार के दो संस्करणों रहे हैं। आप केवल शून्य प्रकार के तरीकों पर ही आह्वान कर सकते हैं। संभावित रूप से अशक्त प्रकारों को नल के लिए स्पष्ट जाँच के माध्यम से नहीं-शून्य प्रकार में परिवर्तित किया जा सकता है। इससे यह जानना बहुत आसान हो जाता है कि अशक्त जाँच कहाँ आवश्यक है और वे कहाँ नहीं हैं।

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

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

38

जावा में आम "समस्या" वास्तव में।

सबसे पहले, इस पर मेरे विचार:

मैं मानता हूं कि जब NULL को कोई वैध मान नहीं है तो NULL पास होने पर कुछ "खाना" करना बुरा है। यदि आप किसी प्रकार की त्रुटि के साथ विधि से बाहर नहीं निकल रहे हैं, तो इसका मतलब है कि आपकी पद्धति में कुछ भी गलत नहीं हुआ है जो सच नहीं है। तब आप शायद इस मामले में अशक्त हो जाते हैं, और प्राप्त करने की विधि में आप फिर से शून्य की जांच करते हैं, और यह कभी समाप्त नहीं होती है, और आप "अगर! = अशक्त", आदि के साथ समाप्त होते हैं।

तो, IMHO, null एक महत्वपूर्ण त्रुटि होनी चाहिए जो आगे निष्पादन को रोकती है (अर्थात, जहाँ null एक वैध मान नहीं है)।

इस समस्या को हल करने का तरीका यह है:

सबसे पहले, मैं इस सम्मेलन का पालन करता हूं:

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

और अंत में, कोड में, सार्वजनिक विधि की पहली पंक्ति इस प्रकार है:

ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();

ध्यान दें कि addParam () स्वयं रिटर्न देता है, ताकि आप जांच करने के लिए अधिक पैरामीटर जोड़ सकें।

यदि कोई पैरामीटर अशक्त validate()है ValidationExceptionतो विधि को चेक किया जाएगा (चेक या अनचेक किया जाना अधिक डिज़ाइन / स्वाद समस्या है, लेकिन मेरी ValidationExceptionजाँच की गई है)।

void validate() throws ValidationException;

संदेश में निम्नलिखित पाठ होगा, उदाहरण के लिए, "योजना" शून्य है:

" अवैध तर्क मान अशक्त पैरामीटर के लिए सामना करना पड़ता है [योजना] "

जैसा कि आप देख सकते हैं, उपयोगकर्ता संदेश के लिए addParam () विधि (स्ट्रिंग) में दूसरे मूल्य की आवश्यकता है, क्योंकि आप आसानी से पारित चर नाम का पता नहीं लगा सकते हैं, यहां तक ​​कि प्रतिबिंब के साथ (वैसे भी इस पोस्ट का विषय नहीं ...)।

और हां, हम जानते हैं कि इस रेखा से परे हम अब एक अशक्त मूल्य का सामना नहीं करेंगे, इसलिए हम उन वस्तुओं पर सुरक्षित तरीके से लागू करते हैं।

इस तरह, कोड साफ, आसान बनाए रखने योग्य और पठनीय है।


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

35

यह सवाल पूछना यह बताता है कि आपको रणनीतियों को संभालने में त्रुटि हो सकती है। आपकी टीम के वास्तुकार को यह तय करना चाहिए कि त्रुटियों को कैसे काम करना है। इसे करने बहुत सारे तरीके हैं:

  1. अपवाद के माध्यम से लहर करने की अनुमति दें - उन्हें 'मुख्य लूप' या किसी अन्य प्रबंध दिनचर्या में पकड़ें।

    • त्रुटि स्थितियों की जांच करें और उन्हें उचित तरीके से संभालें

निश्चित रूप से पहलू ओरिएंटेड प्रोग्रामिंग पर एक नज़र है, वे भी if( o == null ) handleNull()अपने बायोटेक में सम्मिलित करने के लिए स्वच्छ तरीके हैं ।


35

उपयोग करने के अलावा assertआप निम्नलिखित का उपयोग कर सकते हैं:

if (someobject == null) {
    // Handle null here then move on.
}

यह इससे थोड़ा बेहतर है:

if (someobject != null) {
    .....
    .....



    .....
}

2
म्ह, ऐसा क्यों? कृपया किसी भी रक्षात्मक महसूस न करें, मैं सिर्फ जावा के बारे में अधिक जानना चाहूंगा :)
Matthias Meid

9
@ मडु एक सामान्य नियम के रूप में, मैं एक "नकारात्मक" के बजाय एक अधिक "सकारात्मक" कथन होने के लिए अभिव्यक्ति को प्राथमिकता देता हूं। इसलिए अगर मैंने देखा कि if (!something) { x(); } else { y(); }मैं इसे रिफ्लेक्टर के रूप में पसंद करूंगा if (something) { y(); } else { x(); }(हालांकि कोई यह तर्क दे सकता है कि != nullयह अधिक सकारात्मक विकल्प है ...)। लेकिन इससे भी महत्वपूर्ण बात यह है कि कोड का महत्वपूर्ण हिस्सा {}एस के अंदर लपेटा नहीं गया है और आपके पास अधिकांश विधि के लिए इंडेंटेशन का एक स्तर कम है। मुझे नहीं पता कि अगर यह फास्टकोडेजवा का तर्क था, लेकिन यह मेरा होगा।
MatrixFrog

1
यह वही है जो मैं भी करता हूं .. मेरे कोड्सन में कोड को साफ रखता है।
कोरे तुगे

34

बस कभी अशक्त का उपयोग न करें। इसकी अनुमति न दें।

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

एक बार जब मैंने इस प्रथा को अपनाया, तो मैंने देखा कि समस्याएं खुद को ठीक करने लगी थीं। आप विकास की प्रक्रिया में बहुत पहले ही चीजों को दुर्घटना से पकड़ लेते हैं और महसूस कर सकते हैं कि आपके पास एक कमजोर स्थान था .. और अधिक महत्वपूर्ण बात .. यह विभिन्न मॉड्यूल की चिंताओं को सुलझाने में मदद करता है, विभिन्न मॉड्यूल एक-दूसरे पर भरोसा कर सकते हैं, और अधिक कूड़ेदान नहीं if = null elseनिर्माण के साथ कोड !

यह रक्षात्मक प्रोग्रामिंग है और लंबे समय में बहुत क्लीनर कोड में परिणाम है। हमेशा डेटा को पवित्र करें, जैसे कि कठोर मानकों को लागू करने से, और समस्याएं दूर हो जाती हैं।

class C {
    private final MyType mustBeSet;
    public C(MyType mything) {
       mustBeSet=Contract.notNull(mything);
    }
   private String name = "<unknown>";
   public void setName(String s) {
      name = Contract.notNull(s);
   }
}


class Contract {
    public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}

अनुबंध मिनी-यूनिट परीक्षणों की तरह हैं जो हमेशा उत्पादन में भी चल रहे हैं, और जब चीजें विफल हो जाती हैं, तो आप जानते हैं कि क्यों, एक यादृच्छिक एनपीई के बजाय आपको किसी तरह पता लगाना होगा।


इसे क्यों कम किया जाएगा? मेरे अनुभव में, यह अन्य दृष्टिकोणों से कहीं बेहतर है, यह जानना अच्छा लगेगा कि क्यों नहीं
ianpojman

मैं सहमत हूं, यह दृष्टिकोण हर जगह कोड null जाँचों को धब्बा लगाने के बजाय, नल से संबंधित समस्याओं को रोकता है।
क्रिसब्लाम

7
इस दृष्टिकोण के साथ समस्या यह है कि यदि नाम कभी सेट नहीं होता है, तो इसका मूल्य "<अज्ञात>" होता है, जो एक निर्धारित मूल्य की तरह व्यवहार करता है। अब मान लें कि मुझे यह जांचने की आवश्यकता है कि क्या नाम सेट नहीं किया गया था (अज्ञात), मुझे विशेष मूल्य "<अज्ञात>" के खिलाफ एक स्ट्रिंग तुलना करनी होगी।
स्टीव कू डि

1
सही अच्छी बात स्टीव। मेरे पास अक्सर ऐसा मूल्य होता है जो एक स्थिर के रूप में होता है, उदाहरण के लिए सार्वजनिक स्थैतिक अंतिम स्ट्रिंग UNSET = "__ परेशान" ... निजी स्ट्रिंग फ़ील्ड = UNSET ... फिर निजी बूलियन सेट () {वापसी UNSET.equals (फ़ील्ड); }
ianpojman

IMHO, यह अपने आप में वैकल्पिक (अनुबंध) के कार्यान्वयन के साथ नल ऑब्जेक्ट पैटर्न का कार्यान्वयन है। यह दृढ़ता वर्ग वर्ग पर कैसे व्यवहार करता है? मैं उस मामले में लागू नहीं देखता हूं।
कुरपिका 19

31

Google द्वारा बहुत उपयोगी कोर लाइब्रेरी, अमरूद, नल से बचने के लिए एक अच्छा और उपयोगी एपीआई है। मुझे UseAndAvoidingNullExplained बहुत मददगार लगता है ।

जैसा कि विकि में समझाया गया है:

Optional<T>एक अशक्त टी संदर्भ को एक अशक्त मान के साथ बदलने का एक तरीका है। एक वैकल्पिक में या तो एक गैर-शून्य टी संदर्भ हो सकता है (जिस स्थिति में हम कहते हैं कि संदर्भ "वर्तमान" है), या इसमें कुछ भी नहीं हो सकता है (जिस स्थिति में हम कहते हैं कि संदर्भ "अनुपस्थित" है)। यह कभी नहीं कहा जाता है "अशक्त होते हैं।"

उपयोग:

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

@ कोडीगुलनेर राइट, कोडी। मैंने अधिक संदर्भ देने के लिए लिंक से एक प्रासंगिक उद्धरण प्रदान किया।
मुरात दरिया

25

यह हर जावा डेवलपर के लिए एक बहुत ही आम समस्या है। तो इन समस्याओं के निपटारे के बिना जावा 8 में आधिकारिक समर्थन है।

जावा 8 पेश किया है java.util.Optional<T>। यह एक कंटेनर है जो एक गैर-शून्य मान को पकड़ सकता है या नहीं रख सकता है। जावा 8 ने एक वस्तु को संभालने के लिए एक सुरक्षित तरीका दिया है जिसका मूल्य कुछ मामलों में शून्य हो सकता है। यह हास्केल के विचारों से प्रेरित है और स्काला

संक्षेप में, वैकल्पिक वर्ग में उन मामलों से स्पष्ट रूप से निपटने के तरीके शामिल हैं जहां एक मूल्य मौजूद है या अनुपस्थित है। हालांकि, शून्य संदर्भ की तुलना में लाभ यह है कि वैकल्पिक <टी> वर्ग आपको उस मामले के बारे में सोचने के लिए मजबूर करता है जब मूल्य मौजूद नहीं है। परिणामस्वरूप, आप अनपेक्षित नल पॉइंटर अपवाद को रोक सकते हैं।

ऊपर के उदाहरण में हमारे पास एक गृह सेवा कारखाना है जो घर में उपलब्ध कई उपकरणों को संभालता है। लेकिन ये सेवाएं उपलब्ध हो सकती हैं या नहीं / कार्यात्मक; इसका मतलब यह एक NullPointerException में परिणाम हो सकता है। इसके बजाय एक शून्य जोड़ने के लिएifकिसी भी सेवा का उपयोग करने से पहले स्थिति , इसे वैकल्पिक <सेवा> पर लपेटें।

विकल्प के लिए लिखित <टी>

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

public Optional<Service> getRefrigertorControl() {
      Service s = new  RefrigeratorService();
       //...
      return Optional.ofNullable(s);
   }

जैसा कि आप देखते Optional.ofNullable()हैं कि संदर्भ को लपेटने का एक आसान तरीका प्रदान करता है। एक और तरीके वैकल्पिक के संदर्भ पाने के लिए या तो कर रहे हैं, Optional.empty()औरOptional.of() । एक खाली वस्तु को वापस लेने के बजाय अशक्त और दूसरे को गैर-अशक्त वस्तु से लपेटने के लिए क्रमशः।

कितनी जल्दी एक पूर्ण चेक प्राप्त करने में मदद करता है?

एक बार जब आप एक संदर्भ वस्तु लपेटते हैं, तो वैकल्पिक एनपीई के बिना लिपटे संदर्भ पर तरीकों को लागू करने के लिए कई उपयोगी तरीके प्रदान करता है।

Optional ref = homeServices.getRefrigertorControl();
ref.ifPresent(HomeServices::switchItOn);

Optional.ifPresent दिए गए उपभोक्ता को संदर्भ के साथ आमंत्रित करता है यदि यह एक गैर-शून्य मान है। नहीं तो कुछ नहीं करता।

@FunctionalInterface
public interface Consumer<T>

एक ऑपरेशन का प्रतिनिधित्व करता है जो एकल इनपुट तर्क को स्वीकार करता है और कोई परिणाम नहीं देता है। अधिकांश अन्य कार्यात्मक इंटरफेस के विपरीत, उपभोक्ता को साइड-इफेक्ट के माध्यम से संचालित होने की उम्मीद है। यह इतना साफ और समझने में आसान है। उपरोक्त कोड उदाहरण में, HomeService.switchOn(Service)यदि वैकल्पिक होल्डिंग संदर्भ गैर-शून्य है , तो इसे लागू किया जाता है।

अशक्त स्थिति की जाँच के लिए हम एक वैकल्पिक संचालक का उपयोग करते हैं और वैकल्पिक मूल्य या डिफ़ॉल्ट मान लौटाते हैं। वैकल्पिक, नल की जांच के बिना उसी स्थिति को संभालने का एक और तरीका प्रदान करता है। Optional.orElse (defaultObj) डिफॉल्टऑब्ज देता है यदि ऑप्शनल के पास शून्य मान है। इसका उपयोग हमारे नमूना कोड में करें:

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

अब HomeServices.get () वही काम करता है, लेकिन बेहतर तरीके से। यह जांचता है कि क्या सेवा पहले से ही आरंभिक नहीं है। यदि यह है तो उसी को वापस करें या एक नई नई सेवा बनाएं। वैकल्पिक <T> .orElse (T) एक डिफ़ॉल्ट मान लौटाने में मदद करता है।

अंत में, यहाँ हमारा NPE और साथ ही शून्य चेक-फ्री कोड है:

import java.util.Optional;
public class HomeServices {
    private static final int NOW = 0;
    private static Optional<HomeServices> service;

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

public Optional<Service> getRefrigertorControl() {
    Service s = new  RefrigeratorService();
    //...
    return Optional.ofNullable(s);
}

public static void main(String[] args) {
    /* Get Home Services handle */
    Optional<HomeServices> homeServices = HomeServices.get();
    if(homeServices != null) {
        Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl();
        refrigertorControl.ifPresent(HomeServices::switchItOn);
    }
}

public static void switchItOn(Service s){
         //...
    }
}

पूरा पोस्ट NPE के साथ-साथ Null चेक-फ्री कोड है… रियली?


उपरोक्त कोड में एक अशक्त जाँच है - if(homeServices != null) {जिसे परिवर्तित किया जा सकता है homeServices.ifPresent(h -> //action);
कृष्णप्रभाकर

23

मुझे नेट प्राइज के लेख पसंद हैं। यहाँ लिंक हैं:

लेखों में एक जावा शायद प्रकार के लिए एक गिट रिपॉजिटरी का लिंक भी है जो मुझे दिलचस्प लगता है, लेकिन मुझे नहीं लगता कि यह अकेले जाँच कोड ब्लोट को कम कर सकता है। इंटरनेट पर कुछ शोध करने के बाद, मुझे लगता है ! = अशक्त कोड ब्लोट मुख्य रूप से सावधान डिजाइन द्वारा कम किया जा सकता है।



21

मैंने कोशिश की है, NullObjectPatternलेकिन मेरे लिए हमेशा जाने का सबसे अच्छा तरीका नहीं है। कभी-कभी ऐसा होता है जब "कोई कार्रवाई नहीं" नहीं होती है।

NullPointerExceptionएक रनटाइम अपवाद है जिसका अर्थ है कि यह डेवलपर्स की गलती है और पर्याप्त अनुभव के साथ यह आपको बताता है कि त्रुटि कहां है।

अब जवाब देने के लिए:

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

बेशक, अनुभव इस सुझाव को समझने और लागू करने का बेहतर तरीका है।

बाइट!


19

संभवतः जावा 8 या नए के लिए सबसे अच्छा विकल्प Optionalवर्ग का उपयोग करना है ।

Optional stringToUse = Optional.of("optional is there");
stringToUse.ifPresent(System.out::println);

यह संभावित अशक्त मूल्यों की लंबी श्रृंखलाओं के लिए विशेष रूप से आसान है। उदाहरण:

Optional<Integer> i = Optional.ofNullable(wsObject.getFoo())
    .map(f -> f.getBar())
    .map(b -> b.getBaz())
    .map(b -> b.getInt());

नल पर अपवाद कैसे फेंकें, इस पर उदाहरण:

Optional optionalCarNull = Optional.ofNullable(someNull);
optionalCarNull.orElseThrow(IllegalStateException::new);

जावा 7 ने वह Objects.requireNonNullतरीका पेश किया जो तब संभव हो सकता है जब किसी चीज को गैर-अशक्तता के लिए जांचना चाहिए। उदाहरण:

String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();

17

क्या मैं इसका जवाब दे सकता हूँ!

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

इसलिए इसमें कोई अंतर नहीं है:

if(object == null){
   //you called my method badly!

}

या

if(str.length() == 0){
   //you called my method badly again!
}

वे दोनों यह सुनिश्चित करना चाहते हैं कि कोई अन्य कार्य करने से पहले हमें मान्य पैरामीटर मिले।

जैसा कि कुछ अन्य उत्तरों में उल्लेख किया गया है, उपरोक्त समस्याओं से बचने के लिए आप अनुबंध पैटर्न द्वारा डिजाइन का पालन कर सकते हैं । कृपया http://en.wikipedia.org/wiki/Design_by_contract देखें ।

जावा में इस पैटर्न को लागू करने के लिए, आप javaax.annotation.NotNull जैसे कोर जावा एनोटेशन का उपयोग कर सकते हैं या हाइबरनेट वैलिडेटर जैसे अधिक परिष्कृत पुस्तकालयों का उपयोग कर सकते हैं ।

बस एक नमूना:

getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)

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

आप एक कदम आगे जा सकते हैं और यह सुनिश्चित कर सकते हैं कि आपके आवेदन में केवल वैध पॉजोस बनाया जा सकता है। (हाइबरनेट सत्यापनकर्ता साइट से नमूना)

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}

javaxपरिभाषा से, है नहीं "कोर जावा"।
टॉमस

17

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

वास्तव में, अगर किसी विधि से लौटाया गया कुछ अशक्त हो सकता है और कॉलिंग कोड को उस पर निर्णय लेना है, तो एक पूर्व कॉल होना चाहिए जो राज्य को सुनिश्चित करता है।

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

इसके अलावा, मैं इस पैटर्न का उपयोग करने की सिफारिश नहीं करूंगा, जहां टाइप का अर्थ है एक आदिम प्रकार का प्रतिनिधित्व - जैसे गणितीय संस्थाएं, जो स्केलर नहीं हैं: वैक्टर, मैट्रीक, कॉम्प्लेक्स नंबर और पीओडी (प्लेन ओल्ड डेटा) ऑब्जेक्ट्स, जो राज्य को धारण करने के लिए हैं। जावा निर्मित प्रकारों के रूप में। बाद के मामले में आप अनियंत्रित परिणामों के साथ कॉल करने वाले तरीकों को समाप्त करेंगे। उदाहरण के लिए NullPerson.getName () विधि वापस क्या होनी चाहिए?

बेतुके परिणामों से बचने के लिए ऐसे मामलों पर विचार करना लायक है।


"HasBackground ()" के साथ समाधान में एक खामी है - यह थ्रेड-सुरक्षित नहीं है। यदि आपको एक के बजाय दो तरीकों को कॉल करने की आवश्यकता है, तो आपको बहु-थ्रेडेड वातावरण में पूरे अनुक्रम को सिंक्रनाइज़ करने की आवश्यकता है।
पल्किनो

@pkalinow आपने केवल एक आकस्मिक उदाहरण दिया है कि इस समाधान में एक खामी है। यदि कोड मल्टीथ्रेडेड एप्लिकेशन में चलाने के लिए नहीं है, तो कोई खामी नहीं है। मैं शायद आपके ९ ०% कोड को डाल सकता हूं जो कि थ्रेड सुरक्षित नहीं है। हम यहां कोड के इस पहलू के बारे में नहीं बोल रहे हैं, हम डिजाइन पैटर्न के बारे में बोल रहे हैं। और मल्टीथ्रेडिंग अपने आप में एक विषय है।
15:19 बजे luke1985

बेशक एक एकल-थ्रेड अनुप्रयोग में यह कोई समस्या नहीं है। मैंने वह टिप्पणी दी है क्योंकि कभी-कभी यह एक समस्या है।
पल्किनो

@pkalinow यदि आप इस विषय का अध्ययन करते हैं, तो आपको पता चलेगा कि नल ऑब्जेक्ट डिज़ाइन पैटर्न मल्टीथ्रेडिंग समस्याओं को ठीक नहीं करेगा। तो यह अप्रासंगिक है। और ईमानदार होने के लिए, मुझे ऐसी जगहें मिली हैं जहाँ यह पैटर्न अच्छी तरह से फिट होगा, इसलिए मेरा मूल उत्तर वास्तव में थोड़ा गलत है।
luke1985

16
  1. शून्य करने के लिए चर का प्रारंभ न करें।
  2. यदि (1) संभव नहीं है, तो खाली संग्रह / सरणियों के लिए सभी संग्रह और सरणियों को इनिशियलाइज़ करें।

अपने स्वयं के कोड में ऐसा करना और आप बच सकते हैं! = अशक्त चेक।

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

// Bad
ArrayList<String> lemmings;
String[] names;

void checkLemmings() {
    if (lemmings != null) for(lemming: lemmings) {
        // do something
    }
}



// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};

void checkLemmings() {
    for(lemming: lemmings) {
        // do something
    }
}

इसमें एक छोटा ओवरहेड है, लेकिन यह क्लीनर कोड और कम NullPointerException के लिए इसके लायक है।



3
+1 यह मैं इससे सहमत हूं। आपको कभी भी आधा प्रारंभिक ऑब्जेक्ट वापस नहीं करना चाहिए। इसके लिए जैक्सब संबंधित कोड और बीन कोड है। यह बुरा अभ्यास है। सभी संग्रहों को आरंभीकृत किया जाना चाहिए, और सभी वस्तुओं को (आदर्श रूप से) कोई अशक्त संदर्भ नहीं होना चाहिए। उस वस्तु पर विचार करें, जिसमें उसका संग्रह है। यह जाँचना कि वस्तु अशक्त नहीं है, कि संग्रह शून्य नहीं है और यह कि संग्रह में अशक्त वस्तुएं नहीं हैं, अनुचित और मूर्खतापूर्ण है।
ggb667 14

15

यह अधिकांश डेवलपर्स के लिए सबसे सामान्य त्रुटि है।

हमारे पास इसे संभालने के कई तरीके हैं।

दृष्टिकोण 1:

org.apache.commons.lang.Validate //using apache framework

NotNull (ऑब्जेक्ट ऑब्जेक्ट, स्ट्रिंग संदेश)

दृष्टिकोण 2:

if(someObject!=null){ // simply checking against null
}

दृष्टिकोण 3:

@isNull @Nullable  // using annotation based validation

दृष्टिकोण 4:

// by writing static method and calling it across whereever we needed to check the validation

static <T> T isNull(someObject e){  
   if(e == null){
      throw new NullPointerException();
   }
   return e;
}

विज्ञापन। 4. यह बहुत उपयोगी नहीं है - जब आप चेक करते हैं कि कोई पॉइंटर अशक्त है, तो आप शायद इस पर एक विधि कॉल करना चाहते हैं। नल पर एक विधि को कॉल करना आपको समान व्यवहार देता है - NullPointerException।
पल्किनो

11
public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}

2
इस पद्धति में क्या गलत है, मुझे लगता है कि @tltester सिर्फ एक डिफ़ॉल्ट मान देना चाहता है यदि यह शून्य है, जो समझ में आता है।
सॉयर

1
Apache commons-lang में ऐसी एक विधि है ObjectUtils.defaultIfNull():। एक और सामान्य है: ObjectUtils.firstNonNull()जिसका उपयोग अपमानजनक रणनीति को लागू करने के लिए किया जा सकता है:firstNonNull(bestChoice, secondBest, thirdBest, fallBack);
ivant
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.