2015-09-09 13 views
112

हाल ही में मैं स्प्रिंग फ्रेमवर्क का स्रोत कोड पढ़ रहा हूं। कुछ मैं नहीं समझ सकता यहाँ जाता है:जावा टर्नरी ऑपरेटर बनाम/अन्य में <जेडीके 8 संगतता

public Member getMember() { 
    // NOTE: no ternary expression to retain JDK <8 compatibility even when using 
    // the JDK 8 compiler (potentially selecting java.lang.reflect.Executable 
    // as common type, with that new base class not available on older JDKs) 
    if (this.method != null) { 
     return this.method; 
    } 
    else { 
     return this.constructor; 
    } 
} 

इस विधि वर्ग org.springframework.core.MethodParameter का एक सदस्य है। टिप्पणियां मुश्किल होने पर कोड को समझना आसान है।

नोट: कोई त्रिगुट अभिव्यक्ति 8 अनुकूलता भी जब JDK 8 संकलक का उपयोग कर (संभावित java.lang.reflect.Executable के रूप में आम प्रकार का चयन, कि नए आधार वर्ग पुराने JDKs पर उपलब्ध नहीं के साथ)

क्या JDK < बनाए रखने के लिए इस संदर्भ में टर्नरी अभिव्यक्ति का उपयोग करने और if...else... का उपयोग करने के बीच अंतर?

उत्तर

102

जब आप ऑपरेंड के प्रकार के बारे में सोचते हैं, समस्या अधिक स्पष्ट हो जाता है this.constructor

जावा 7 में यह java.lang.reflect.Member है, हालांकि जावा 8 क्लास लाइब्रेरी एक नया प्रकार java.lang.reflect.Executable पेश करती है जो जेनेरिक Member से अधिक विशिष्ट है। इसलिए जावा 8 क्लास लाइब्रेरी के साथ Member की बजाय टर्नरी अभिव्यक्ति का परिणाम प्रकार Executable है।

जावा 8 कंपाइलर के कुछ (प्री-रिलीज) संस्करणों ने टर्नरी ऑपरेटर को संकलित करते समय उत्पन्न कोड के अंदर Executable का एक स्पष्ट संदर्भ प्रस्तुत किया है। यह एक वर्ग लोड ट्रिगर करेगा, और इस तरह बदले में कार्यावधि में एक ClassNotFoundException एक वर्ग पुस्तकालय < JDK 8 के साथ जब चल रहा है, क्योंकि Executable केवल के लिए JDK ≥ 8.

मौजूद this answer में Tagir Valeev द्वारा बताया गया है, यह वास्तव में एक है जेडीके 8 के प्री-रिलीज संस्करणों में बग और तब से तय किया गया है, इसलिए if-else कामकाज और स्पष्टीकरण टिप्पणी अब अप्रचलित हैं।

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

+1

फिर जेडीके 1.8 पर कोड जेडीके 1.8 के साथ संकलित कैसे किया जा सकता है। मुझे पता चला है कि कम संस्करण जेडीके के साथ संकलित कोड बिना किसी परेशानी के उच्च संस्करण जेडीके पर चला सकता है। वीसा बनाम? – jddxf

+1

@jddxf सब कुछ ठीक है जब तक आप उचित वर्ग फ़ाइल संस्करण निर्दिष्ट करते हैं और किसी भी कार्यक्षमता का उपयोग नहीं करते जो बाद के संस्करणों में उपलब्ध नहीं है। समस्या होने वाली है, हालांकि यदि इस तरह के उपयोग इस मामले में निहित रूप से होते हैं। – dhke

+13

@jddxf, उपयोग -सोर्स/-टाइटल javac विकल्प –

7

मुख्य अंतर यह है कि एक ifelse ब्लॉक एक बयान है जबकि त्रिगुट (अधिक बार जावा में सशर्त ऑपरेटर के रूप में जाना जाता है) एक अभिव्यक्ति है।

कथन कुछ नियंत्रण पथों पर कॉलर को return जैसी चीजें कर सकता है। एक अभिव्यक्ति एक काम में इस्तेमाल किया जा सकता है:

int n = condition ? 3 : 2;

तो हालत के बाद त्रिगुट में दो भाव एक ही प्रकार के लिए coercable की जरूरत है। इससे विशेष रूप से ऑटो-मुक्केबाजी और स्वचालित संदर्भ कास्टिंग के साथ जावा में कुछ अजीब प्रभाव हो सकते हैं - यही आपके पोस्ट कोड में टिप्पणी का जिक्र है। आपके मामले में अभिव्यक्तियों का जबर java.lang.reflect.Executable प्रकार (जैसा कि सबसे विशिष्ट प्रकार) है और यह जावा के पुराने संस्करणों में मौजूद नहीं है।

स्टाइलिस्टिक रूप से आपको ifelse ब्लॉक का उपयोग करना चाहिए यदि कोड कथन जैसा है, और एक टर्नरी अगर यह अभिव्यक्ति की तरह है।

बेशक, यदि आप लैम्ब्डा फ़ंक्शन का उपयोग करते हैं तो आप ifelse ब्लॉक अभिव्यक्ति की तरह व्यवहार कर सकते हैं।

6

एक त्रिगुट अभिव्यक्ति में वापसी मान प्रकार माता पिता कक्षाएं, जो जावा 8.

हार्ड में वर्णित के रूप को देखने के लिए क्यों एक डाली लिखा गया है नहीं कर सका बदल से प्रभावित है।

this.method != null ? this.method : this.constructor 

दोनों ऑपरेंड के सबसे विशेष आम प्रकार प्रकार के रूप में है, दोनों this.method और करने के लिए आम सबसे विशेष प्रकार अर्थात्:

30

यह 3 मई 2013 को quite old commit में पेश किया गया था, लगभग एक साल पहले आधिकारिक जेडीके -8 रिहाई। संकलक उस समय भारी विकास के अधीन था, इसलिए ऐसी संगतता समस्याएं हो सकती हैं। मुझे लगता है, स्प्रिंग टीम ने सिर्फ जेडीके -8 बिल्ड का परीक्षण किया और समस्याओं को ठीक करने की कोशिश की, भले ही वे वास्तव में संकलक समस्याएं हैं। जेडीके -8 आधिकारिक रिलीज द्वारा यह अप्रासंगिक हो गया। अब इस कोड में टर्नरी ऑपरेटर अपेक्षित के रूप में ठीक काम करता है (संकलित में Executable वर्ग का कोई संदर्भ नहीं है। क्लास-फ़ाइल मौजूद है)।

वर्तमान में जेडीके-9 में समान चीजें दिखाई देती हैं: जेडीके -8 में अच्छी तरह से संकलित किया जा सकता है कुछ कोड जेडीके-9 जावा के साथ विफल रहा है। मुझे लगता है, इस तरह की अधिकांश समस्याओं को रिलीज तक तय किया जाएगा।

+2

+1 दिया है। तो, क्या यह शुरुआती कंपाइलर में एक बग था? क्या वह व्यवहार था, जहां इसे 'निष्पादन योग्य' कहा जाता था, जो कि spec के कुछ पहलू का उल्लंघन करता था? या यह सिर्फ इतना है कि ओरेकल को एहसास हुआ कि वे इस व्यवहार को इस तरह से बदल सकते हैं जो अभी भी spec के अनुरूप होगा और पिछड़े-संगतता को तोड़ने के बिना? – ruakh

+2

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

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