जावा में, क्या मुझे पैरामीटर और स्थानीय लोगों के लिए "अंतिम" का उपयोग करना चाहिए, जब मेरे पास नहीं है?


105

जावा finalउन्हें पुनः असाइन करने से रोकने के लिए, चर (फ़ील्ड / स्थानीय / पैरामीटर) को चिह्नित करने की अनुमति देता है। मुझे यह खेतों के साथ बहुत उपयोगी लगता है, क्योंकि यह मुझे जल्दी से यह देखने में मदद करता है कि क्या कुछ विशेषताएँ - या एक पूरी कक्षा - अपरिवर्तनीय हैं।

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

अब मेरी प्रोग्रामिंग शैली के बारे में आश्वस्त नहीं हूं, मुझे आश्चर्य है कि finalकहीं भी आवेदन करने के अन्य फायदे और नुकसान क्या हैं , सबसे आम उद्योग शैली क्या है, और क्यों।


@Amir कोडिंग-शैली के प्रश्न यहाँ SO से बेहतर हैं, और मैं इस बारे में अक्सर पूछे जाने वाले प्रश्न या इस साइट के मेटा पर कोई नीति नहीं खोज सका। क्या आप मुझे निर्देशित कर सकते हैं?
ओक

1
@ ऑक यह कहता है: "विशिष्ट प्रोग्रामिंग समस्या, सॉफ्टवेयर एल्गोरिदम, कोडिंग , स्टैक ओवरफ्लो पर पूछें"
आमिर रज़ाई

7
@ मैं असहमत हूं, मैं नहीं देखता कि यह एक कोडिंग समस्या कैसे है। किसी भी मामले में यह बहस यहाँ नहीं है, इसलिए मैंने इस मुद्दे पर एक मेटा-विषय खोला है ।
ओक

3
@ आमिर इस साइट के लिए पूरी तरह से विषय पर है, क्योंकि यह प्रोग्रामिंग के बारे में एक व्यक्तिपरक सवाल है - कृपया देखें / faq
जेफ एटवुड

1
पुन: स्थानीय चर: पुराने जावा कंपाइलरों ने इस बात पर ध्यान दिया कि आपने स्थानीय घोषित किया है finalया नहीं और उसी के अनुसार अनुकूलित किया गया है। आधुनिक संकलक इतने स्मार्ट हैं कि वे इसे अपने लिए समझ सकें। कम से कम स्थानीय चर पर, finalकड़ाई से मानव पाठकों के लाभ के लिए है। यदि आपकी दिनचर्या बहुत जटिल नहीं है, तो अधिकांश मानव पाठकों को इसका पता लगाने में सक्षम होना चाहिए।
सोलोमन स्लो

जवाबों:


67

मैं finalउसी तरह का उपयोग करता हूं जैसे आप। मेरे लिए यह स्थानीय चर और विधि मापदंडों पर बहुत ही अच्छा लग रहा है, और यह उपयोगी अतिरिक्त जानकारी को व्यक्त नहीं करता है।

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

इसके अलावा, जैसा कि आप निश्चित रूप से जानते हैं, finalगारंटी नहीं है कि आप (nonprimitive) चर का मान / स्थिति नहीं बदल सकते। केवल यह कि आप उस ऑब्जेक्ट के संदर्भ को एक बार आरंभीकृत नहीं कर सकते । दूसरे शब्दों में, यह केवल मूल या अपरिवर्तनीय प्रकारों के चर के साथ काम करता है। विचार करें

final String s = "forever";
final int i = 1;
final Map<String, Integer> m = new HashMap<String, Integer>();

s = "never"; // compilation error!
i++; // compilation error!
m.put(s, i); // fine

इसका मतलब यह है कि कई मामलों में अभी भी यह समझना आसान नहीं है कि कोड के अंदर क्या होता है, और यह गलतफहमी वास्तव में सूक्ष्म कीड़े का कारण बन सकती है जो कि पता लगाना मुश्किल है।


1
संपादित करें के बारे में - मैं के शब्दार्थ से अवगत हूँ final, धन्यवाद :) लेकिन लघु और स्वच्छ विधियों के बारे में अच्छी बात है - मुझे लगता है कि यदि विधि इतनी कम है कि यह स्पष्ट है कि एक चर फिर से सौंपा नहीं जा रहा है, तो finalकीवर्ड पर विचार करने के लिए भी कम मकसद ।
ओक

क्या यह बहुत अच्छा नहीं होगा यदि हम अंतिम पैरामीटर और स्थानीय चर, और अभी भी एक छोटा और साफ वाक्यविन्यास कर सकते हैं? programmers.stackexchange.com/questions/199783/...
oberlies

7
"अंतिम गारंटी नहीं देता है कि आप (गैर-अप्रभावी) चर के मूल्य / स्थिति को बदल नहीं सकते हैं। केवल यह कि आप एक बार आरम्भ करने के बाद उस वस्तु के संदर्भ को पुन: असाइन नहीं कर सकते।" अप्रतिसादी = संदर्भ (जावा में केवल प्रकार आदिम प्रकार और संदर्भ प्रकार हैं)। संदर्भ प्रकार का एक चर का मान है एक संदर्भ। इसलिए, आप संदर्भ को पुन: असाइन नहीं कर सकते हैं = आप मान नहीं बदल सकते।
user102008

2
संदर्भ / राज्य के नुकसान के लिए +1। ध्यान दें कि Java8 के नए कार्य पहलुओं में क्लोजर बनाने के लिए वैरिएबल फाइनल को चिन्हित करना आवश्यक हो सकता है
Newtopian

आपकी तुलना पक्षपाती है क्योंकि @ user102008 ने बताया है। वैरिएबल असाइनमेंट इसके वैल्यू अपडेट के समान नहीं है
एरियन

64

आपकी जावा प्रोग्रामिंग शैली और विचार ठीक हैं - खुद पर संदेह करने की जरूरत नहीं है।

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

यही कारण है कि आपको finalकीवर्ड का उपयोग करना चाहिए । आप कहते हैं कि आप जानते हैं कि इसे कभी भी दोबारा नहीं सौंपा जाएगा, लेकिन यह कोई और नहीं जानता। finalतुरंत उपयोग करने से आपका कोड छोटा हो जाता है।


8
यदि आपका तरीका स्पष्ट है और केवल एक ही चीज पाठक को भी पता चल जाएगा। अंतिम शब्द केवल कोड को अपठनीय बनाता है। और अगर इसके अपठनीय इसके बहुत अधिक अस्पष्ट
eddieferetro

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

4
क्या "आशय" है कि चर कभी नहीं बदलेगा, और आपका कोड उस तथ्य पर निर्भर करता है ? या इरादे "यह सिर्फ इतना होता है कि यह चर कभी नहीं बदलता है इसलिए मैं इसे अंतिम रूप से चिह्नित कर रहा हूं"। बाद में बेकार है और संभवतः हानिकारक शोर है। और चूंकि आप सभी स्थानीय लोगों को चिह्नित करने की वकालत करते हैं, आप बाद में कर रहे हैं। बड़ा -1।
user949300

2
finalआशय बताता है, जो आमतौर पर कोड के एक टुकड़े में एक अच्छी बात है, लेकिन यह दृश्य अव्यवस्था को जोड़ने की कीमत पर आता है। प्रोग्रामिंग की अधिकांश चीजों की तरह, यहां एक व्यापार बंद है: इस तथ्य को व्यक्त करना कि आपका चर केवल वर्बोसिटी के लायक केवल एक बार उपयोग किया जा रहा है?
christopheml

30

उपयोग करने का एक फायदा final/ constजहाँ भी संभव हो यह आपके कोड के पाठक के लिए मानसिक भार को कम करता है।

वह निश्चिंत हो सकता है, कि मूल्य / संदर्भ को बाद में कभी नहीं बदला जाएगा। इसलिए उन्हें गणना को समझने के लिए संशोधनों पर ध्यान देने की आवश्यकता नहीं है।

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


16
खैर, जावा finalमें यह गारंटी नहीं है कि आप (गैर-अप्रतिस्पर्धी) चर का मान / स्थिति नहीं बदल सकते। केवल यह कि आप उस ऑब्जेक्ट के संदर्भ को एक बार आरंभीकृत नहीं कर सकते ।
Péter Török

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

7
@ PéterTörök यह आदिम प्रकारों के साथ तुरंत मददगार है, और उत्परिवर्तित वस्तुओं के संदर्भ में कुछ हद तक सहायक है (कम से कम आप जानते हैं कि आप हमेशा एक ही वस्तु के साथ काम कर रहे हैं!)। जमीन से अपरिवर्तनीय होने के लिए डिज़ाइन किए गए कोड के साथ काम करते समय यह बहुत उपयोगी है।
एंड्रेस एफ।

18

मैं finalविधि पैरामीटर और स्थानीय चर को कोड शोर मानता हूं । जावा विधि घोषणाएं काफी लंबी हो सकती हैं (विशेष रूप से जेनरिक के साथ) - उन्हें अब और बनाने की कोई आवश्यकता नहीं है।

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

FindBugs और CheckStyle जैसे उपकरण जिन्हें निर्माण को तोड़ने के लिए कॉन्फ़िगर किया जा सकता है यदि असाइनमेंट को पैरामीटर या स्थानीय चर के लिए बनाया गया है, अगर आप ऐसी चीजों के बारे में गहराई से ध्यान रखते हैं।

बेशक, यदि आपको उन्हें अंतिम रूप देने की आवश्यकता है, उदाहरण के लिए क्योंकि आप एक अनाम वर्ग में मूल्य का उपयोग कर रहे हैं, तो कोई समस्या नहीं है - यह सबसे सरल सबसे साफ समाधान है।

अपने मापदंडों में अतिरिक्त कीवर्ड जोड़ने के स्पष्ट प्रभाव के अलावा, और जिससे IMHO उन्हें छलाँग लगाता है, अंतिम रूप से विधि मापदंडों को जोड़कर अक्सर विधि बॉडी में कोड को कम पठनीय बनाया जा सकता है, जो कोड को बदतर बनाता है - "अच्छा" होने के लिए, कोड जितना संभव हो उतना पठनीय और सरल होना चाहिए। एक आकस्मिक उदाहरण के लिए, कहो कि मेरे पास एक तरीका है जिसे असंवेदनशील तरीके से काम करने की आवश्यकता है।

इसके बिना final:

public void doSomething(String input) {
    input = input.toLowerCase();
    // do a few things with input
}

सरल। स्वच्छ। हर कोई जानता है कि क्या हो रहा है।

अब 'अंतिम' के साथ, विकल्प 1:

public void doSomething(final String input) {
    final String lowercaseInput = input.toLowerCase();
    // do a few things with lowercaseInput
}

मापदंडों को बनाते समय finalकोडर को जोड़ने से यह सोचकर कि वह मूल मूल्य के साथ काम कर रहा है, से नीचे रोक देता है, एक समान जोखिम है कि कोड नीचे और नीचे उपयोग कर सकता inputहै lowercaseInput, जिसे इसे नहीं करना चाहिए और जिसके खिलाफ आपकी रक्षा नहीं की जा सकती, क्योंकि आप कर सकते हैं ' टी इसे दायरे से बाहर ले जाएं (या यहां तक कि अगर यह भी मदद करेगा तो असाइन nullकरें input)।

'अंतिम' के साथ, विकल्प 2:

public void doSomething(final String input) {
    // do a few things with input.toLowerCase()
}

अब हम सिर्फ और भी अधिक कोड शोर बना रहे हैं और एक प्रदर्शन हिट शुरू करने के लिए toLowerCase()n बार आह्वान किया है।

'अंतिम' के साथ, विकल्प 3:

public void doSomething(final String input) {
    doSomethingPrivate(input.toLowerCase());
}

/** @throws IllegalArgumentException if input not all lower case */
private void doSomethingPrivate(final String input) {
    if (!input.equals(input.toLowerCase())) {
        throw new IllegalArgumentException("input not lowercase");
    }
    // do a few things with input
}

कोड शोर के बारे में बात करें। यह एक ट्रेन का कहर है। हमें एक नई विधि, एक आवश्यक अपवाद ब्लॉक मिला है, क्योंकि अन्य कोड इसे गलत तरीके से लागू कर सकते हैं। अपवाद को कवर करने के लिए अधिक इकाई परीक्षण। सभी एक सरल, और IMHO से बचने के लिए बेहतर और हानिरहित, लाइन।

यह भी समस्या है कि विधियां इतनी लंबी नहीं होनी चाहिए कि आप आसानी से इसे नेत्रहीन रूप से नहीं ले सकते हैं और एक नज़र में जानते हैं कि पैरामीटर के लिए एक असाइनमेंट हुआ है।

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


ध्यान दें कि finalयह वास्तव में आपकी रक्षा नहीं करता है जैसे कि यह पहली बार लगता है:

public void foo(final Date date) {
    date.setTime(0); 
    // code that uses date
}

final जब तक पैरामीटर प्रकार आदिम या अपरिवर्तनीय नहीं है, तब तक आप पूरी तरह से रक्षा नहीं करते हैं।


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

+1 जोखिम की ओर इशारा करने के लिए "वह कोड आगे नीचे इनपुट का उपयोग कर सकता है"। फिर भी, मैं finalऊपर दिए गए मामलों के लिए उन्हें गैर-अंतिम बनाने की संभावना के साथ अपने मापदंडों को प्राथमिकता देना चाहूंगा। यह सिर्फ एक खोजशब्द के साथ हस्ताक्षर स्पैमिंग के लायक नहीं है।
Maaartinus

7

मैंने finalप्रत्येक स्थानीय चर से पहले ग्रहण करने दिया , क्योंकि मैं इस कार्यक्रम को पढ़ना आसान बनाता हूं। मैं इसे मापदंडों के साथ नहीं बनाता, क्योंकि मैं पैरामीटर सूची को यथासंभव छोटा रखना चाहता हूं, आदर्श रूप से इसे एक पंक्ति में फिट होना चाहिए।


2
इसके अलावा, मापदंडों के लिए, आप कंपाइलर को चेतावनी या त्रुटि दे सकते हैं यदि कोई पैरामीटर असाइन किया गया है।
oberlies

3
इसके विपरीत, मुझे यह पढ़ने में कठिन लगता है क्योंकि यह कोड को पूरा करता है।
स्टीव कू

3
@ सेव कुओ: यह सिर्फ मुझे जल्दी से सभी चर खोजने की अनुमति देता है। कोई बड़ा लाभ नहीं है, लेकिन एक साथ आकस्मिक कार्य को रोकने के लिए यह 6 वर्णों के लायक है। अगर varगैर-अंतिम चर को चिह्नित करने के लिए कुछ ऐसा था, तो मुझे बहुत खुशी होगी । YMMV।
मैार्टिनस

1
@maaartinus के बारे में सहमत var! दुर्भाग्य से यह जावा में डिफ़ॉल्ट नहीं है और अब भाषा को बदलने में बहुत देर हो चुकी है। इसलिए, मैं लिखने की मामूली असुविधा के साथ तैयार होना चाहता हूं final:)
एंड्रेस एफ।

1
@aaartinus सहमत हैं। मुझे लगता है कि मेरे (स्थानीय) चरों के लगभग find०- ९ ०% को आरंभीकरण के बाद संशोधित करने की आवश्यकता नहीं है। इसलिए, उनमें से final, var
०-
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.