2014-04-10 29 views
25
public class Npe { 
    static class Thing { 
     long value; 
    } 

    public static Map<Thing, Long> map; 

    public static void main(String[] args) { 
     Thing thing = new Thing(); 
     method(null); // returns -1 
     method(thing); // returns 0 
     map = new HashMap<Thing, Long>(); 
     method(null); // returns -1 
     method(thing); // NullPointerException thrown inside this method call 
    } 

    public static long method(Thing thing) { 
     if (thing == null) { 
      return -1; 
     } 
     Long v = (map == null) ? thing.value : map.get(thing); // NPE here 
     if (v == null) { 
      v = thing.value; 
     } 
     return v; 
    } 
} 

method() को 4 कॉल पर मैं एक NullPointerExceptionmethod() अंदर संकेत लाइन पर फेंक दिया मिलता है। अगर मैंयह असाइनमेंट एनपीई क्यों करता है?

Long v; 
if (map == null) { 
    v = thing.value; 
} else { 
    v = map.get(thing); 
} 

को

Long v = (map == null) ? thing.value : map.get(thing); 

से कि लाइन refactor मुझे कोई NullPointerException हो और एकदम सही ढंग से विधि व्यवहार करता है। सवाल यह है: क्यों ??

यह संकलक की तरह मुझे लग रहा है की उम्मीद है, जिससे कि वह (Long से long को अवनत) map.get(thing) करने के लिए कॉल (जो null वापस आ सकते हैं और इसलिए एक फेंक का परिणाम unboxing है ? ऑपरेटर का परिणाम long होने के लिए NullPointerException)। आईएमएचओ को ? ऑपरेटर के परिणाम Long और ऑटोबॉक्सिंग (long से Long) thing.value के परिणामस्वरूप होने की उम्मीद करनी चाहिए।

और भी बेहतर, अगर मैं इस बयान refactor:

Long v = (map == null) ? thing.value : map.get(thing); 
इस के लिए

(Long को long कास्टिंग स्पष्ट रूप से):

Long v = (map == null) ? (Long)thing.value : map.get(thing); 

मेरी आईडीई (इंटेलीजे) का कहना है कि कलाकारों बेमानी है, लेकिन संकलित कोड अपेक्षित काम करता है और NullPointerException फेंक नहीं देता है! ,

(map == null) ? thing.value : map.get(thing) 

कि अभिव्यक्ति का परिणाम long होगा, क्योंकि thing.value के प्रकार long है: :-D

+2

[बूलियन, सशर्त ऑपरेटर और ऑटोबॉक्सिंग] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/3882095/booleans-conditional-operators-and-autoboxing) –

+10

@DwB आपकी टिप्पणी प्रासंगिक नहीं है क्योंकि मैं नहीं हूं कनिष्ठ प्रोग्रामर। और आपका सुझाव "टर्नरी ऑपरेटर का उपयोग नहीं" करने के लिए भी मूर्खतापूर्ण है। सिर्फ इसलिए कि कुछ जटिल या भ्रमित हो सकता है जिसका मतलब यह नहीं है कि आपको इसका उपयोग नहीं करना चाहिए। इसका मतलब यह है कि आपको सावधान रहना होगा और पता होना चाहिए कि आप क्या कर रहे हैं। यदि डेवलपर्स ने जटिल या संभावित रूप से भ्रमित करने वाली किसी भी चीज का कभी भी उपयोग नहीं किया है, तो वे सभी प्रोग्रामर के बजाय पेंटर्स या स्ट्रीट स्वीपर या गार्डनर्स होंगे ;-) –

+1

यदि आप 'टर्नरी ऑपरेटर को नहीं समझते हैं, तो, विश्वास करें या नहीं, आप अभी भी जूनियर हैं जावा। साथ ही, तथ्य यह है कि कुछ जटिल, उलझन में है, और कोई मूल्य प्रदान नहीं करता है इसका उपयोग करने का एक बड़ा कारण नहीं है। यदि डेवलपर्स ने कभी भी जटिल और संभावित रूप से भ्रमित करने वाली किसी भी चीज का उपयोग नहीं किया है, तो वे कोड उत्पन्न करेंगे जो कम अनावश्यक रूप से जटिल और भ्रमित है। – DwB

उत्तर

28

अपने सशर्त अभिव्यक्ति पर विचार करें। JLS §15.25 - Conditional Operator देखें। जेएलएस 8 में टेबल एक बढ़िया जोड़ा है। यह विभिन्न इनपुट प्रकारों के लिए सभी संभावित आउटपुट प्रकारों को स्पष्ट करता है। सशर्त अभिव्यक्ति के प्रकार से संबंधित भ्रम इतना था।

अब जब आप इस विधि के रूप में आह्वान:

method(thing); 

mapnull नहीं है, तो हालत map == null अपने अभिव्यक्ति में false का मूल्यांकन, और फिर इसे map.get(thing) का मूल्यांकन करता है परिणाम प्राप्त करने के।

चूंकि map में अभी तक कोई प्रविष्टि नहीं है, map.get(thing)null वापस आ जाएगा। लेकिन चूंकि परिणाम का प्रकार long है, इसलिए null पर एक अनबॉक्सिंग ऑपरेशन किया जाता है, जिसके परिणामस्वरूप NPE होता है।


अब जब आप स्पष्ट रूप से Long को thing.value डाली, अभिव्यक्ति के प्रकार Long हो जाता है। इसलिए map.get(thing) के परिणामस्वरूप कोई अनबॉक्सिंग नहीं किया गया है, और null को Long v पर असाइन किया गया है।

+4

* सामान्य * जावा गॉचा :) –

+0

आप क्यों कहते हैं कि अभिव्यक्ति का परिणाम 'लंबा' होगा? मैं कहूंगा कि अभिव्यक्ति का परिणाम 'लांग' है, क्योंकि तीसरा तर्क' लांग' है। –

+1

@ डेविड वासर सशर्त अभिव्यक्ति का परिणाम दूसरे और तीसरे ऑपरेंड के प्रकार पर निर्भर करता है। न सिर्फ ऑपरेंड पर जो उत्तर देने जा रहा है। जेएलएस लिंक में तालिका देखें। यदि कोई भी ऑपरेंड आदिम प्रकार है, तो परिणाम प्राचीन प्रकार होगा। –

0

यह क्या हो रहा है की मेरी समझ है:

जब आप Long v = (map == null) ? thing.value : map.get(thing); // NPE here

map.get(thing) रिटर्न एक Long कि है null का उपयोग और उसके बाद (long लिए अपने मूल्य Unbox क्योंकि अभिव्यक्ति प्रकार के प्रयास नहीं है यदि लंबा हो) - यह एनपीई का कारण बनता है।

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

+0

ठीक है मैं आईई के एक संस्करण का उपयोग कर रहा हूं जो जल्द से जल्द अद्यतनों को दिखाने में विश्वास नहीं करता है, और 22 मिनट के भीतर कम से कम नहीं :) – Bhaskar

संबंधित मुद्दे