java - बचना!=शून्य बयान





object nullpointerexception null (25)


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

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

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

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

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

उदाहरण के लिए:

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

यह एक NullPointerException से बचाता है, जब यह अज्ञात है यदि ऑब्जेक्ट null या नहीं।

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




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

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

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

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

हो जाता है

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



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

  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जो उन शर्तों को इंगित करता है जो एक उचित अनुप्रयोग पकड़ना चाहते हैं ( javadoc )! अपवादों के पहले सबसे अधिक लाभ और 'नियमित' कोड ( जावा के रचनाकारों के अनुसार ) से अलग त्रुटि-हैंडलिंग कोड का उपयोग करने के लिए यह मेरे लिए, पकड़ने के लिए उपयुक्त है NullPointerException

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

    प्रश्न उठ सकते हैं:

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

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

    प्र। इस दृष्टिकोण के बंद होने के प्रयास के कारण प्रदर्शन दंड है।
    ए सॉफ्टवेयर को पहले समझने और संशोधित करना आसान होना चाहिए। इसके बाद, कोई प्रदर्शन के बारे में सोच सकता है, और केवल तभी आवश्यक हो सकता है! और जहां आवश्यक हो! ( source ), और कई अन्य)।

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

    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);
    }
    

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




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

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




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

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

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

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

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

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




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

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

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

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

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

assert <condition>

या

assert <condition> : <object>

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

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

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

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

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

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

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();

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

उस ने कहा, शायद यह निष्कर्ष निकालने के लिए findAction () विधि के लिए एक सार्थक त्रुटि संदेश के साथ एक अपवाद फेंकने के लिए पूरी तरह से उपयुक्त है - खासकर इस मामले में जहां आप उपयोगकर्ता इनपुट पर भरोसा कर रहे हैं। बिना किसी स्पष्टीकरण के एक सरल 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);
        }
    }
}



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

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

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

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



    .....
}



आप किस प्रकार की ऑब्जेक्ट्स की जांच कर रहे हैं, इस पर निर्भर करते हुए आप अपाचे कॉमन्स में कुछ कक्षाओं का उपयोग करने में सक्षम हो सकते हैं जैसे: apache commons lang और apache commons संग्रह

उदाहरण:

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

या (आपको जो जांचने की आवश्यकता है उसके आधार पर):

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

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

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

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");



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

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

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

उपरोक्त उदाहरण में हमारे पास एक घरेलू सेवा कारखाना है जो घर में उपलब्ध कई उपकरणों के लिए एक हैंडल देता है। लेकिन ये सेवाएं उपलब्ध / कार्यात्मक नहीं हो सकती हैं या नहीं; इसका मतलब है कि इसका परिणाम नलपॉन्टर अपवाद में हो सकता है। 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);

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

@FunctionalInterface
public interface Consumer<T>

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

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

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

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

अंत में, यहां हमारे एनपीई के साथ-साथ शून्य चेक-फ्री कोड भी है:

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){
         //...
    }
}

पूरी पोस्ट एनपीई के साथ ही नल चेक-फ्री कोड है ... वास्तव में?




क्या मैं इसे अधिक आम तौर पर उत्तर दे सकता हूं!

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

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

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 देखें ।

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

बस एक नमूना:

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

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

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

public class Car {

   @NotNull
   private String manufacturer;

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

   @Min(2)
   private int seatCount;

   // ...
}



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

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

शून्य / नोटन पैराम्स में सहायता के लिए जावा 7 में नई एनोटेशन जोड़ने का एक प्रस्ताव है: http://tech.puredanger.com/java7/#jsr308




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

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

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

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

जिस तरह से मैं इस समस्या को हल करता हूं यह है:

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

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

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

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

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

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

void validate() throws ValidationException;

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

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

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

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

इस तरह, कोड स्वच्छ, आसान रखरखाव और पठनीय है।




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

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

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

उपयोग:

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



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

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

एक बार मैंने इस अभ्यास को अपनाया, मैंने देखा कि समस्याएं खुद को ठीक करने लगती हैं। आप केवल दुर्घटना से विकास प्रक्रिया में चीजों को पकड़ लेंगे और महसूस करेंगे कि आपके पास कमजोर जगह थी .. और सबसे महत्वपूर्ण बात यह है कि यह विभिन्न मॉड्यूल की चिंताओं को समाहित करने में मदद करता है, विभिन्न मॉड्यूल एक-दूसरे पर भरोसा कर सकते हैं, और अब और कूड़ेदान नहीं कर सकते के साथ कोड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; }
}

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




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

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



शायद जावा 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();



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

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

दृष्टिकोण 1:

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

नहीं शून्य (ऑब्जेक्ट ऑब्जेक्ट, स्ट्रिंग संदेश)

दृष्टिकोण 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;
}



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

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

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

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

  • यह स्पष्ट रूप से एपीआई में कहा गया है कि कोई इनपुट या आउटपुट मौजूद है या नहीं।
  • कंपाइलर आपको "अपरिभाषित" केस को संभालने के लिए मजबूर करता है।
  • विकल्प एक मोनैड है , इसलिए वर्बोज़ नल जांच की कोई आवश्यकता नहीं है, केवल मूल्य (example) सुरक्षित) का उपयोग करने के लिए मानचित्र / foreach / getOrElse या एक समान संयोजक का उपयोग करें।

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

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




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

असल में, आपको @Nullable और @Nullable मिल गया है।

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

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

या

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

दूसरा उदाहरण संकलित नहीं होगा (इंटेलिजे आईडीईए में)।

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

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

अब इंटेलिजे आईडीईए कंपाइलर आपको बताएगा कि चेक बेकार है, क्योंकि helloWorld() फ़ंक्शन null वापस नहीं लौटाएगा।

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

void someMethod(@NotNull someParameter) { }

यदि आप कुछ लिखते हैं:

someMethod(null);

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

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

@Nullable iWantToDestroyEverything() { return null; }

यह कर रहा हूं

iWantToDestroyEverything().something();

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

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

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

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




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

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

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

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

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

बाइट!




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




  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
    }
}

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




जावा 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();
}

अब इस कोड को देखें जहां हम fruits दिए गए फल उदाहरण के लिए 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 द्वारा लाया गया है: जावा वैकल्पिक ऑब्जेक्ट्स




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

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

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 && ... "।

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




ऐसा लगता है कि एक IllegalArgumentException लिए कहा जाता है यदि आप null को अनुमत मान नहीं चाहते हैं, और यदि आप एक चर का उपयोग करने की कोशिश कर रहे थे तो NullPointerException फेंक दिया जाएगा जो null हो जाता है।





java object nullpointerexception null