Boolean.valueOf () कभी-कभी NullPointerException उत्पन्न करता है


115

मेरे पास यह कोड है:

package tests;

import java.util.Hashtable;

public class Tests {

    public static void main(String[] args) {

        Hashtable<String, Boolean> modifiedItems = new Hashtable<String, Boolean>();

        System.out.println("TEST 1");
        System.out.println(modifiedItems.get("item1")); // Prints null
        System.out.println("TEST 2");
        System.out.println(modifiedItems.get("item1") == null); // Prints true
        System.out.println("TEST 3");
        System.out.println(Boolean.valueOf(null)); // Prints false
        System.out.println("TEST 4");
        System.out.println(Boolean.valueOf(modifiedItems.get("item1"))); // Produces NullPointerException
        System.out.println("FINISHED!"); // Never executed
    }
}

मेरी समस्या यह है कि मुझे समझ में नहीं आता है कि टेस्ट 3 ठीक क्यों काम करता है (यह प्रिंट falseकरता है और उत्पादन नहीं करता है NullPointerException) इस बीच टेस्ट 4 फेंकता है NullPointerException। जैसा कि आप परीक्षण 1 और 2 में देख सकते हैं , nullऔर modifiedItems.get("item1")बराबर हैं और null

जावा 7 और 8 में व्यवहार समान है।


यह एक शून्य है, लेकिन आप मान लेते हैं कि इस मान को पास करना एक एनपीई में समाप्त नहीं होगा?
स्टूलटस्के

16
@Stultuske: यह एक वैध प्रश्न है, यह देखते हुए कि एक nullही फ़ंक्शन को शाब्दिक रूप से पास करने के लिए सिर्फ दो लाइनें एक NPE उत्पन्न नहीं करती हैं! इसका एक अच्छा कारण है, लेकिन यह निश्चित रूप से पहली नजर में भ्रामक है :-)
Psmears

25
मैं प्रसन्न हूँ। यह सबसे दिलचस्प अशक्त सूचक अपवाद प्रश्न है जिसे मैंने वर्षों में देखा है।
candied_orange

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

जवाबों:


178

आप ध्यान से देखने के लिए मिल गया है जिस पर अधिभार का आह्वान किया जा रहा है:

  • Boolean.valueOf(null)आह्वान कर रहा है Boolean.valueOf(String)। यह NPEएक अशक्त पैरामीटर के साथ दिए जाने पर भी नहीं फेंकता है ।
  • Boolean.valueOf(modifiedItems.get("item1"))आह्वान कर रहा है Boolean.valueOf(boolean), क्योंकि modifiedItemsमूल्य प्रकार के होते हैं Boolean, जिसके लिए एक अनबॉक्सिंग रूपांतरण की आवश्यकता होती है। के बाद से modifiedItems.get("item1")है null, यह है कि मूल्य के unboxing है - न Boolean.valueOf(...)- जो एनपीई फेंकता है।

यह निर्धारित करने के लिए कि कौन से अधिभार का आह्वान किया जाता है , वे सुंदर बालों वाले होते हैं , लेकिन वे मोटे तौर पर इस तरह जाते हैं:

  • पहले पास में, बॉक्सिंग / अनबॉक्सिंग (और न ही वेरिएबल एरिटी मेथड्स) की अनुमति के बिना एक विधि मिलान खोजा जाता है।

    • क्योंकि nullएक के लिए एक स्वीकार्य मूल्य है String, लेकिन नहीं boolean, Boolean.valueOf(null)करने के लिए मिलान किया जाता है Boolean.valueOf(String)यह पास में;
    • Booleanया तो के लिए एक स्वीकार्य नहीं है Boolean.valueOf(String)या Boolean.valueOf(boolean)नहीं, कोई विधि के लिए यह पास में मिलान किया जाता है तो Boolean.valueOf(modifiedItems.get("item1"))
  • एक दूसरे पास में, बॉक्सिंग / अनबॉक्सिंग (लेकिन अभी भी वैरिएबल एरिटी मेथड नहीं) की अनुमति के लिए एक विधि मिलान खोजा जाता है।

    • A Booleanको अनबॉक्स किया जा सकता है boolean, इसलिए इस पास में Boolean.valueOf(boolean)मिलान किया Boolean.valueOf(modifiedItems.get("item1"))जाता है; लेकिन एक अनबॉक्सिंग रूपांतरण को इसे लागू करने के लिए संकलक द्वारा सम्मिलित किया जाना है:Boolean.valueOf(modifiedItems.get("item1").booleanValue())
  • (वेरिएबल एरिटी मेथड के लिए एक तीसरा पास की अनुमति है, लेकिन यह यहां प्रासंगिक नहीं है, क्योंकि पहले दो पास इन मामलों से मेल खाते हैं)


3
यदि हम Boolean.valueOf(modifiedItems.get("item1").booleanValue())इसके बजाय स्रोत कोड में उपयोग करते हैं तो कोड अधिक स्पष्ट हो सकता है Boolean.valueOf(modifiedItems.get("item1"))?
कौंसिंगउंडरफ़्लोज़ प्रत्येक

1
@CausingUnderflowsEverywhere वास्तव में नहीं है - .booleanValue()अभिव्यक्ति में दफन यह देखना वास्तव में कठिन है । दो अवलोकनों: 1) ऑटो (संयुक्त राष्ट्र) मुक्केबाजी सिंटैक्टिक क्रॉफ़्ट को हटाने के लिए जावा की एक जानबूझकर विशेषता है; स्वयं करना संभव है, लेकिन मुहावरेदार नहीं; 2) यह आपकी बिल्कुल मदद नहीं करता है - यह निश्चित रूप से समस्या को होने से नहीं रोकता है, और न ही विफलता होने पर कोई अतिरिक्त जानकारी देता है (स्टैक ट्रेस समान होगा, क्योंकि निष्पादित कोड समान है)।
एंडी टर्नर

@CausingUnderflowsEverywhere इस मुद्दे को उजागर करने के लिए टूलींग का उपयोग करना बेहतर है, उदाहरण के लिए intellij आप यहाँ संभावित NPE के बारे में अर्जित करेंगे।
एंडी टर्नर

13

चूँकि modifiedItems.getरिटर्न Boolean(जो कि कास्टेबल नहीं है String), रिटर्न का उपयोग किया जाएगा Boolean.valueOf(boolean), जहां Booleanएक आदिम के लिए आउटबॉक्स किया गया है boolean। एक बार nullवहाँ लौटने के बाद, आउटबॉक्सिंग विफल रहता है a NullPointerException


11

विधि हस्ताक्षर

विधि Boolean.valueOf(...)के दो हस्ताक्षर हैं:

  1. public static Boolean valueOf(boolean b)
  2. public static Boolean valueOf(String s)

आपका modifiedItemsमूल्य है Boolean। आप डाली नहीं कर सकते Booleanकरने के लिए Stringइतना फलस्वरूप पहले हस्ताक्षर चुना जाएगा

बूलियन अनबॉक्सिंग

अपने बयान में

Boolean.valueOf(modifiedItems.get("item1"))

जो के रूप में पढ़ा जा सकता है

Boolean.valueOf(modifiedItems.get("item1").booleanValue())   

हालाँकि, modifiedItems.get("item1")रिटर्न nullइतना है कि आप मूल रूप से होगा

null.booleanValue()

जो स्पष्ट रूप से होता है NullPointerException


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

4
मेरे खाते पर इसे न हटाएं। याद रखें, यह एक शून्य-राशि का खेल नहीं है: लोग कई उत्तरों को बढ़ा सकते हैं (और कर सकते हैं)।
एंडी टर्नर

3

जैसा कि एंडी पहले से ही बहुत अच्छी तरह से इसका कारण बताता है NullPointerException:

जो बुलियन अन-बॉक्सिंग के कारण है:

Boolean.valueOf(modifiedItems.get("item1"))

में परिवर्तित हो:

Boolean.valueOf(modifiedItems.get("item1").booleanValue())

रनटाइम पर और फिर इसे फेंक NullPointerExceptionअगर modifiedItems.get("item1")रिक्त है।

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

  1. बाइट - बाइट
  2. चरित्र - चरित्र
  3. फ्लोट - फ्लोट
  4. int - पूर्णांक
  5. लम्बा लम्बा
  6. लघु - लघु
  7. दुगुना दुगुना

यहाँ कोड है:

    Hashtable<String, Boolean> modifiedItems1 = new Hashtable<String, Boolean>();
    System.out.println(Boolean.valueOf(modifiedItems1.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Byte> modifiedItems2 = new Hashtable<String, Byte>();
    System.out.println(Byte.valueOf(modifiedItems2.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Character> modifiedItems3 = new Hashtable<String, Character>();
    System.out.println(Character.valueOf(modifiedItems3.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Float> modifiedItems4 = new Hashtable<String, Float>();
    System.out.println(Float.valueOf(modifiedItems4.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Integer> modifiedItems5 = new Hashtable<String, Integer>();
    System.out.println(Integer.valueOf(modifiedItems5.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Long> modifiedItems6 = new Hashtable<String, Long>();
    System.out.println(Long.valueOf(modifiedItems6.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Short> modifiedItems7 = new Hashtable<String, Short>();
    System.out.println(Short.valueOf(modifiedItems7.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Double> modifiedItems8 = new Hashtable<String, Double>();
    System.out.println(Double.valueOf(modifiedItems8.get("item1")));//Exception in thread "main" java.lang.NullPointerException

1
"रनटाइम में परिवर्तित ..." संकलन समय में इसे परिवर्तित कर दिया गया है।
एंडी टर्नर

0

इसे समझने का एक तरीका यह है कि जब Boolean.valueOf(null)आह्वान किया जाता है, तो जावा को ठीक-ठीक बताया जाता है।

हालांकि, जब Boolean.valueOf(modifiedItems.get("item1"))आह्वान किया जाता है, तो जावा को ऑब्जेक्ट प्रकार बूलियन के हैशटेबल से एक मान प्राप्त करने के लिए कहा जाता है, लेकिन यह बूलियन टाइप नहीं करता है क्योंकि यह बूलियन की अपेक्षा होने पर भी (शून्य) एक मृत अंत पाता है। NullPointerException अपवाद को फेंक दिया गया है क्योंकि जावा के इस हिस्से के रचनाकारों ने फैसला किया कि यह स्थिति प्रोग्राम में कुछ गलत होने का एक उदाहरण है जिसे प्रोग्रामर का ध्यान देने की आवश्यकता है। (अनायास ही कुछ हुआ)

इस मामले में यह जानबूझकर घोषित करने के बीच का अंतर है कि आपने नल को वहां होने का इरादा किया है, और जावा एक ऑब्जेक्ट (नल) का एक लापता संदर्भ ढूंढ रहा है जहां एक ऑब्जेक्ट को खोजने का इरादा था।

इस उत्तर में NullPointerException के बारे में अधिक जानकारी देखें: https://stackoverflow.com/a/25721181/4425643


अगर कोई इस उत्तर को बेहतर बनाने में मदद कर सकता है, तो मैं एक ऐसे शब्द के बारे में सोच रहा था जो प्रोग्रामर को स्पष्ट इरादे के साथ कुछ लिखने के लिए संदर्भित करता है, जिसमें कोई अस्पष्टता नहीं है
CausingUnderflowsEverywhere
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.