2010-02-02 28 views
15

इस जावा कोड के लिए:जावैक प्रारंभिक चर के बारे में क्यों शिकायत करता है?

String var; 
clazz.doSomething(var); 

क्यों संकलक रिपोर्ट इस त्रुटि करता है: सभी चर या संदर्भ

Variable 'var' might not have been initialized

मैंने सोचा था कि null के लिए शुरू किया गया था। आपको ऐसा करने की आवश्यकता क्यों है:

String var = null; 

??

उत्तर

23

इंस्टेंस और क्लास वेरिएबल्स को शून्य (या 0) में प्रारंभ किया गया है, लेकिन स्थानीय चर नहीं हैं।

एक बहुत विस्तृत विवरण जो मूल रूप से एक ही बात कहते हैं के लिए JLS की §4.12.5 देखें:

Every variable in a program must have a value before its value is used:

  • Each class variable, instance variable, or array component is initialized with a default value when it is created:
    • [snipped out list of all default values]
  • Each method parameter is initialized to the corresponding argument value provided by the invoker of the method.
  • Each constructor parameter is initialized to the corresponding argument value provided by a class instance creation expression or explicit constructor invocation.
  • An exception-handler parameter is initialized to the thrown object representing the exception.
  • A local variable must be explicitly given a value before it is used, by either initialization or assignment, in a way that can be verified by the compiler using the rules for definite assignment.
+1

यह निर्णय क्यों लिया गया था? क्लास वेरिएबल्स की तरह उन्हें 'शून्य' क्यों न करें? –

+0

शायद बेहतर कोड/पठनीयता के लिए? –

+0

स्थानीय चर के डिफ़ॉल्ट होने के संबंध में कई स्टैक ओवरफ्लो प्रश्न हैं। जैसे http://stackoverflow.com/questions/415687/why-are-local-variables-not-initialized-in-java –

7

यह क्योंकि जावा बहुत (संभव के रूप में ज्यादा के रूप में) उपयोगी किया जा रहा है।

यह कुछ ही रोचक किनारे-मामलों को पकड़ने के लिए इस तर्क का उपयोग करेगा जो आप याद कर सकते हैं। उदाहरण के लिए:

int x; 

if(cond2) 
    x=2; 
else if(cond3) 
    x=3; 

System.out.println("X was:"+x); 

यह विफल हो जाएगा क्योंकि एक और मामला निर्दिष्ट नहीं था। तथ्य यह है कि, यहां एक और मामला बिल्कुल निर्दिष्ट किया जाना चाहिए, भले ही यह सिर्फ एक त्रुटि हो (भले ही डिफ़ॉल्ट के बारे में सही हो: स्विच स्टेटमेंट में स्थिति)।

आपको इससे क्या दूर लेना चाहिए, दिलचस्प रूप से पर्याप्त है, कभी भी अपने स्थानीय चर शुरू नहीं करते हैं जब तक आप यह नहीं समझते कि आपको वास्तव में ऐसा करना है। यदि आप हमेशा "int x = 0;" कहने की आदत में हैं आप कार्य करने से इस शानदार "खराब तर्क" डिटेक्टर को रोक देंगे। इस त्रुटि ने मुझे एक बार से अधिक समय बचाया है।

4

डिट्टो विधेयक लालकृष्ण पर मैं जोड़ें:

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

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

जैसा कि बिल कहता है, आपको निश्चित रूप से स्वचालित रूप से आदत नहीं मिलनी चाहिए जब आप उन्हें घोषित करते हैं तो वैरिएबल प्रारंभ करना। केवल घोषणा कार्यक्रम में वैरिएबल प्रारंभ करें यदि यह वास्तव में आपके प्रोग्राम के संदर्भ में समझ में आता है। जैसे, 99% बार आप x को 42 होना चाहते हैं, लेकिन कुछ IF स्थिति के अंदर आप पाएंगे कि यह एक विशेष मामला है और x 666 होना चाहिए, फिर ठीक है, "int x = 42;" से शुरू करें और आईएफ के अंदर इसे ओवरराइड करें। लेकिन अधिक सामान्य मामले में, जहां आप किसी भी परिस्थिति के आधार पर मूल्य को समझते हैं, तो मनमाना संख्या में प्रारंभ न करें। बस इसे गणना मूल्य के साथ भरें।फिर यदि आप तर्क त्रुटि करते हैं और शर्तों के कुछ संयोजन के तहत मूल्य निर्धारित करने में असफल होते हैं, तो संकलक आपको बता सकता है कि आप उपयोगकर्ता की बजाय खराब हो गए हैं।

पी एस मैं लंगड़ा प्रोग्राम हैं जो तरह बातें कहते हैं की एक बहुत कुछ देखा है:

HashMap myMap=new HashMap(); 
myMap=getBunchOfData(); 

क्यों चर प्रारंभ करने के लिए जब आप जानते हैं कि आप तुरंत इस वस्तु की दूरी पर एक millisecond बाद में फेंक करने जा रहे हैं एक वस्तु बनाने के? यह सिर्फ समय की बर्बादी है।

संपादित

एक छोटी सी उदाहरण लेते हैं, मान लीजिए आप यह लिखा:

int foo; 
if (bar<0) 
    foo=1; 
else if (bar>0) 
    foo=2; 
processSomething(foo); 

यह संकलन समय पर एक त्रुटि फेंक होगा, क्योंकि संकलक देखेंगे कि जब बार == 0, आपने कभी भी foo सेट नहीं किया है, लेकिन फिर आप इसका उपयोग करने का प्रयास करते हैं।

लेकिन अगर आप एक डमी मूल्य के लिए foo प्रारंभ, जैसे

int foo=0; 
if (bar<0) 
    foo=1; 
else if (bar>0) 
    foo=2; 
processSomething(foo); 

फिर संकलक देखेंगे कि कोई बात नहीं क्या पट्टी के मूल्य, foo कुछ करने के लिए सेट हो जाता है, तो यह एक त्रुटि का उत्पादन नहीं होगा। यदि आप वास्तव में चाहते हैं कि फू 0 के लिए 0 है, तो बार 0 है, तो यह ठीक है। लेकिन अगर वास्तव में हुआ तो यह है कि आप < = या> = के लिए परीक्षणों में से एक का मतलब था या जब आप बार == 0 के लिए अंतिम फ़ाइनल शामिल करना चाहते थे, तो आपने संकलक को अपनी त्रुटि का पता लगाने में विफल होने में धोखा दिया है। और वैसे, इस तरह से मुझे लगता है कि ऐसा निर्माण खराब कोडिंग शैली है: न केवल संकलक यह सुनिश्चित कर सकता है कि आप क्या चाहते हैं, लेकिन भविष्य में रखरखाव प्रोग्रामर भी नहीं।

+0

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

+0

@ सिबिबिबा: मेरे उत्तर का मेरा क्या हिस्सा आप जवाब दे रहे हैं? यदि आप सामान्य रूप से मतलब रखते हैं, तो आप संकलन-समय की जांच का लाभ खो देंगे। बिल के जवाब देखें। यदि आपका मतलब है मैपैप उदाहरण के साथ मेरी समापन टिप्पणी, तो आसान समाधान "हैश मैप myMap = getBunchOfData()" लिखना और व्यर्थ अतिरिक्त वस्तु को छोड़ना है। – Jay

1

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

तो मैं वापस चला गया और, आरंभीकरण मैं का उपयोग किया था हटाया उदाहरण

List <Thing> somethings = new List<Thing>(); 
somethings.add(somethingElse); // <--- this is completely unnecessary 

नाइस के लिए। मुझे

List<Thing> somethings = new List(); 

और मुझे लगता है कि समस्या प्रारंभिकता की कमी थी। गलत। समस्या यह थी कि मुझे नियमों को समझ में नहीं आया था और मुझे <Thing> "नए" में पहचाना गया था, <Thing> प्रकार की कोई वास्तविक वस्तु नहीं बनाई गई थी।

(अगला मैं कैसे डाल करने के लिए शाब्दिक से कम और HTML में संकेत अधिक से अधिक सीखने की जरूरत है!)

+0

@ बिल IV मैंने आपके लिए उद्धरण साफ़ किए; आपको बस कोड कोड को कोड के रूप में नामित करना है (संपादक के ऊपर 101/010 आइकन इसे करेगा)। –

+0

धन्यवाद, कार्ल! –

0

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

MyClass cls; 
if (condition) { 
    cls = something; 
else 
    cls = something_else; 
0

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

बिल IV

+0

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

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

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