2012-10-06 120 views
11

मैंने टर्नरी ऑपरेटर में एक अप्रत्याशित प्रकार-कास्ट के कारण दूसरे दिन वास्तव में अजीब NullPointerException पार किया। इस (बेकार अनुकरणीय) समारोह को देखते हुए:जावा टर्नरी ऑपरेटर के ऑटो-मुक्केबाजी-व्यवहार के माध्यम से NullPointerException

Integer getNumber() { 
    return null; 
} 

मैं संकलन के बाद बिल्कुल समान होना करने के लिए निम्न दो कोड खंडों उम्मीद कर रहा था:

Integer number; 
if (condition) { 
    number = getNumber(); 
} else { 
    number = 0; 
} 

बनाम

Integer number = (condition) ? getNumber() : 0; 

, if -statement ठीक काम करता है निकलती है तो conditiontrue है, जबकि दूसरा कोड खंड में त्रिगुट opration एक NullPointerException फेंकता है। ऐसा लगता है कि टर्नरी ऑपरेशन ने ऑटो-मुक्केबाजी से पहले में परिणाम दोनों विकल्पों को int पर टाइप-कास्ट करने का निर्णय लिया है! वास्तव में, अगर मैंने स्पष्ट रूप से 0 को Integer पर डाला है, तो अपवाद दूर हो जाता है। दूसरे शब्दों में:

Integer number = (condition) ? getNumber() : (Integer) 0; 

:

Integer number = (condition) ? getNumber() : 0; 

नहीं के समान है।

तो, ऐसा लगता है कि टर्नरी ऑपरेटर और समकक्ष if-else -स्टेटमेंट (कुछ जो मुझे उम्मीद नहीं थी) के बीच बाइट-कोड अंतर है। जो तीन प्रश्न उठाता है: इसमें कोई अंतर क्यों है? क्या यह टर्नरी कार्यान्वयन में एक बग है या क्या टाइप कास्ट का कोई कारण है? यह देखते हुए कि एक अंतर है, क्या टर्नरी ऑपरेशन बराबर if -स्टेटमेंट (मुझे पता है, अंतर बड़ा नहीं हो सकता है, लेकिन अभी भी) की तुलना में कम या ज्यादा प्रदर्शन करने वाला है?

+6

आप गंभीरता से मानते हैं कि दस्तावेज़ के उपयोग और ऑपरेटर के प्रतिबंधों की आपकी * समझ * के बजाय टर्नरी ऑपरेटर में एक बग है? आपको क्या लगता है कि इस वास्तविक रूप से होने वाली बाधाएं हैं? अपने प्रश्न के शीर्षक को "टर्नरी ऑपरेटर कैसे काम करता है" में गलतफहमी को बदलने पर विचार करें। –

+1

यही कारण है कि मैं सवाल पूछ रहा हूं कि क्यों संकलक निर्णय लेता है कि getNumber() और 0 दोनों को int को मूल्यांकन करना चाहिए यदि मैं एक इंटीजर को परिणाम सौंपता हूं। मेरे लिए, तुलना के बाद वास्तव में आवश्यक प्रकार की तुलना में तुलना के मुकाबले दो प्रकार के अधिक प्रतिबंधक को दो तर्कों को डालने का बिल्कुल कोई मतलब नहीं है। Unboxing के माध्यम से क्यों जाना है और फिर getNumber() reboxing? –

+0

इससे कोई फर्क नहीं पड़ता कि आपको क्या लगता है या मुझे लगता है * होना चाहिए। इसके बजाय जो भी मायने रखता है वह जेएलएस में स्पष्ट रूप से दस्तावेज किया गया है। –

उत्तर

13

JLS के अनुसार: -

एक सशर्त अभिव्यक्ति के प्रकार के रूप में निम्न प्रकार निर्धारित किया जाता है:

  • दूसरे और तीसरे ऑपरेंड एक ही प्रकार है (जो अशक्त प्रकार हो सकता है) , तो वह सशर्त अभिव्यक्ति का प्रकार है।
  • यदि दूसरे और तीसरे ऑपरेटरों में से एक आदिम प्रकार टी का है, और दूसरा प्रकार का मुक्केबाजी रूपांतरण
    (§5.1.7) टी को लागू करने का परिणाम है, तो सशर्त अभिव्यक्ति का प्रकार टी है
+1

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

+0

@ मार्कस .. ठीक है, आप यह नहीं कह सकते कि कोई प्रदर्शन अंतर है या नहीं .. यह निश्चित रूप से प्रोग्रामर को कोडिंग की सुविधा देता है .. लेकिन हाँ, क्योंकि इसमें 'अनबॉक्सिंग' का छोटा हिस्सा शामिल है .. जो मामले में नहीं है यदि और अन्य .. तो प्रदर्शन कम हो जाएगा .. –

+0

@ मार्कस .. लेकिन दिया गया है कि टर्नरी ऑपरेटर का उपयोग ज्यादातर 'एकल' कथन की स्थिति के मामले में किया जाता है ..तो, यह चिंता का अधिक नहीं है .. बेशक आप पूरी अभिव्यक्ति को किसी अन्य से अवरुद्ध करने में सक्षम नहीं होंगे- अन्यथा टर्नरी ऑपरेटर को ब्लॉक करें .. तो, उनमें से दोनों पेशेवर और विपक्ष हैं .. –

11

समस्या यह है कि यह है:

Integer number = (condition) ? getNumber() : 0; 

एक unboxing और getNumber के परिणाम की reboxing बाध्य करता है()। ऐसा इसलिए है क्योंकि टर्नरी (0) का झूठा हिस्सा एक पूर्णांक है, इसलिए यह getNumber() को int में परिणाम बदलने की कोशिश करता है। जबकि निम्नलिखित नहीं है:

Integer number = (condition) ? getNumber() : (Integer) 0; 

यह एक बग नहीं है, जिस तरह जावा ने चीजों को करने का विकल्प चुना है।

+0

बिल्कुल, लेकिन क्यों? –

+2

@ मार्कस [जावा भाषा विनिर्देश 15.25] देखें (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25) 'यदि दूसरे और तीसरे में से एक ऑपरेंड आदिम प्रकार टी का है, और दूसरे का प्रकार मुक्केबाजी रूपांतरण (§5.1.7) को टी में लागू करने का परिणाम है, फिर सशर्त अभिव्यक्ति का प्रकार टी। – halex

2

इस तरह यह काम करना चाहिए। टर्नरी ऑपरेटर नियमित if कथन के बराबर होना था। if और else के शव, जबकि भागों निम्नलिखित ? और : रहे भाव, कि एक ही प्रकार के लिए मूल्यांकन करने के लिए आवश्यक हैं बयान हैं।

एक और तरीका रखें: a = b ? c : dif (b) a = c; else a = d; के बराबर नहीं होना चाहिए। इसके बजाए, b ? c : d अपने आप पर एक अभिव्यक्ति है, और इसके परिणामस्वरूप a का परिणाम परिणाम को प्रभावित नहीं करेगा।