समय के साथ एक स्थिर मूल्य को बदला जा सकता है?


28

विकास के चरण के दौरान, कुछ चर ऐसे होते हैं जिन्हें एक ही समय में तय करने की आवश्यकता होती है, लेकिन समय के साथ उन्हें संशोधित करने की आवश्यकता हो सकती है। उदाहरण के लिए एक booleanडीबग मोड को संकेत करने के लिए, इसलिए हम उस कार्यक्रम में काम करते हैं जो हम सामान्य रूप से नहीं करेंगे।

क्या इन मूल्यों final static int CONSTANT = 0को जावा में स्थिर रूप में रखना बुरा है ? मुझे पता है कि रन टाइम के दौरान एक स्थिर रहता है, लेकिन क्या अनियोजित बदलावों को छोड़कर पूरे विकास के दौरान भी ऐसा ही होना चाहिए?

मैंने ऐसे ही सवालों की तलाश की, लेकिन ऐसा कुछ भी नहीं मिला, जो मेरा बिल्कुल मेल खाता हो।


11
मैं उत्सुक हूं, आप इसे बदलने के लिए बुरा स्टाइल क्यों मानेंगे?
विन्सेंट सवार्द

36
जब तक आप स्थिरांक के साथ भौतिक गुणों को मॉडलिंग कर रहे हैं, जो गणितीय मूल्यों को जानते हैं, कुछ समय में सब कुछ बदल सकता है।
बेरिन लोरिट्श 14

19
सॉफ्टवेयर नरम है
एरिक Eidt

10
@GregT मैं असहमत होगा। finalआपको एक संकलित-लागू गारंटी देता है कि कार्यक्रम मूल्य को संशोधित नहीं करेगा। मैं उसके साथ दूर नहीं जाऊंगा क्योंकि प्रोग्रामर स्रोत कोड में निर्दिष्ट मूल्य को संशोधित करना चाहता है।
अलेक्जेंडर - मोनिका

10
एक पूर्ण उत्तर को स्पष्ट करने के लिए ज्यादा समय नहीं है, लेकिन मुझे संदेह है कि आपके सहकर्मियों की चिंता स्थिरांक के साथ बहुत अधिक नहीं है, लेकिन कॉन्फ़िगरेशन मूल्यों के कोड-इनलाइनिंग के साथ, जो स्थिरांक के रूप में प्रकट हो सकते हैं। ... लगातार गलती आपको बेवकूफ गलतियों से बचाती है, जैसे गलती से gravityमिड-गेम / रन पर असाइन करना । जरूरी नहीं कि उनका मतलब gravityहर ग्रह पर एक ही हो ... उन्होंने कहा, स्वस्थ समाधान gravityएक निरंतर बनाने के लिए है, लेकिन इसे planetसंबंधित दायरे की शुरुआत में फाइल या डेटाबेस से खींचना है ।
svidgen

जवाबों:


6

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

यह जावा के डिजाइन में एक मस्सा है, क्योंकि यह बहुत कम मामलों में से एक है (शायद एकमात्र मामला) जहां स्रोत संगतता और बाइनरी संगतता समान नहीं हैं। इस मामले को छोड़कर, आप निर्भरता रखने वाले उपयोगकर्ताओं के बिना नए API- संगत संस्करण के साथ एक निर्भरता को स्वैप कर सकते हैं। जाहिर है कि यह बेहद महत्वपूर्ण है जिस तरह से जावा निर्भरता को आमतौर पर प्रबंधित किया जाता है।

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

अधिक परेशान करने वाली बात यह है कि आज के JVM आसानी से प्रदर्शन के दंड के बिना रनटाइम के सभी स्थिरांक को आसानी से इनलाइन कर सकते हैं (स्थिरांक को परिभाषित करने वाले वर्ग को लोड करने की आवश्यकता के अलावा, जो शायद वैसे भी लोड हो रहा है), दुर्भाग्य से JIT से पहले के दिनों से भाषा की तारीख का शब्दार्थ । और वे भाषा को बदल नहीं सकते क्योंकि तब पिछले संकलक के साथ संकलित कोड सही नहीं होगा। बगड़-अनुकूलता फिर से प्रहार करती है।

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

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


85

constघोषित वैश्विक स्थिरांक सहित आपके स्रोत कोड में कुछ भी, आपके सॉफ़्टवेयर की नई रिलीज़ के साथ परिवर्तन के अधीन हो सकता है।

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

// DO NOT CHANGE without consulting with the legal department!
// Get written consent form from them before release!
public const int LegalLimitInSeconds = ...

अपने भविष्य के आत्म के साथ संवाद करने का एक बेहतर तरीका है।


11
मुझे भविष्य की यह टिप्पणी वास्तव में पसंद आई।
ग्रेग

4
TaxRateकिया जा रहा है publicमुझे परेशान करता है। मैं यह सुनिश्चित करना चाहता हूं कि इस परिवर्तन से प्रभावित केवल बिक्री विभाग और हमारे आपूर्तिकर्ता भी जो हमें कर वसूलते हैं। कौन जानता है कि उस टिप्पणी के बाद से कोड आधार में क्या हुआ है।
कैंडिड_ओरेंज ange

3
@IllusiveBrian स्थिरांक के उपयोग की आलोचना नहीं कर रहा था। एक टिप्पणी पर भरोसा करने के खिलाफ आज तक चेतावनी दे रहा था। हमेशा यह सुनिश्चित करें कि किसी चीज को बदलने से पहले उसका उपयोग कैसे किया जाए।
कैंडिड_ओरेंज

8
यह जावा के लिए अच्छी सलाह है । यह अन्य भाषाओं में भिन्न हो सकती है। उदाहरण के लिए, जिस तरह से C # में कॉल साइट के लिए कॉन्स्टेबल वैल्यूज़ बाध्य हैं, public constफ़ील्ड्स का उपयोग केवल उन्हीं चीज़ों के लिए किया जाना चाहिए , जो कभी-कभी बदलती रहें, जैसे Math.pi. यदि आप एक पुस्तकालय बना रहे हैं public static readonly, तो विकास के दौरान या एक नए संस्करण के साथ चीजें बदल सकती हैं , ताकि आपके पुस्तकालय के उपयोगकर्ताओं के साथ समस्या न हो।
ग्रैंडऑनर

6
आपको एक अलग उदाहरण चुनना चाहिए ... मनी वैल्यू कभी भी फ्लोटिंग पॉइंट नहीं होनी चाहिए!
corsiKa

13

हमें स्थिरांक के दो पहलुओं को अलग करने की आवश्यकता है:

  • विकास समय पर ज्ञात मूल्यों के नाम, जिन्हें हम बेहतर रखरखाव के लिए पेश करते हैं, और
  • मान जो संकलक के लिए उपलब्ध हैं।

और फिर एक संबंधित तीसरा प्रकार है: चर जिसका मान नहीं बदलता है, अर्थात मान के लिए नाम। इन अपरिवर्तनीय चर और स्थिरांक के बीच का अंतर तब होता है जब मूल्य निर्धारित / असाइन / प्रारंभ किया जाता है: एक चर को रनटाइम पर आरंभीकृत किया जाता है, लेकिन एक निरंतर का मान विकास के दौरान जाना जाता है। यह अंतर थोड़ा मैला है क्योंकि एक मूल्य विकास के दौरान जाना जा सकता है लेकिन वास्तव में केवल आरंभीकरण के दौरान बनाया गया है।

लेकिन यदि किसी स्थिरांक का मान संकलन-समय पर ज्ञात होता है, तो संकलक उस मान के साथ संगणना कर सकता है। उदाहरण के लिए, जावा भाषा में निरंतर अभिव्यक्ति की अवधारणा है । एक स्थिर अभिव्यक्ति किसी भी अभिव्यक्ति है जिसमें केवल प्राथमिक या स्ट्रिंग के शाब्दिक होते हैं, निरंतर अभिव्यक्ति (जैसे कि कास्टिंग, इसके अलावा, स्ट्रिंग संयोजन) और निरंतर चर पर संचालन। [ JLS J15.28 ] एक स्थिर चर एक finalचर है जिसे एक स्थिर अभिव्यक्ति के साथ आरंभ किया जाता है। [JLS this4.12.4] जावा के लिए तो, यह एक संकलन-समय स्थिर है:

public static final int X = 7;

यह तब दिलचस्प हो जाता है जब कई संकलन इकाइयों में एक स्थिर चर का उपयोग किया जाता है, और फिर घोषणा को बदल दिया जाता है। विचार करें:

  • A.java:

    public class A { public static final int X = 7; }
  • B.java:

    public class B { public static final int Y = A.X + 2; }

अब जब हम इन फाइलों को संकलित करते हैं तो B.classबायटेकोड एक क्षेत्र घोषित करेगा Y = 9क्योंकि B.Yएक स्थिर चर है।

लेकिन जब हम A.Xवैरिएबल को एक अलग मान (कहते हैं X = 0) में बदल देते हैं और केवल A.javaफ़ाइल को फिर से जोड़ते हैं , तब B.Yभी पुराने मान को संदर्भित करता है। यह राज्य A.X = 0, B.Y = 9स्रोत कोड में घोषणाओं के साथ असंगत है। खुश डिबगिंग!

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

स्थिरांक की प्रकृति के आधार पर, वे डेवलपर्स द्वारा गलत धारणाओं का कारण बन सकते हैं। यदि इन मानों को बदल दिया जाता है, तो वे बग को ट्रिगर कर सकते हैं। उदाहरण के लिए, स्थिरांक का एक सेट चुना जा सकता है ताकि वे कुछ निश्चित पैटर्न बना सकें, जैसे public static final int R = 4, W = 2, X = 1। यदि इन्हें अलग संरचना बनाने के लिए बदल दिया जाए R = 0, W = 1, X = 2तो मौजूदा कोड जैसे कि boolean canRead = perms & Rगलत हो जाता है। और सिर्फ मजाक के बारे में सोचें जो कि Integer.MAX_VALUEबदल जाएगा! यहां कोई फिक्स नहीं है, यह याद रखना महत्वपूर्ण है कि कुछ स्थिरांक का मूल्य वास्तव में महत्वपूर्ण है और बस बदला नहीं जा सकता है।

लेकिन अधिकांश स्थिरांक उन्हें बदलने के लिए ठीक हैं, जब तक कि उपरोक्त प्रतिबंधों को माना जाता है। एक निरंतर परिवर्तन तब सुरक्षित होता है जब अर्थ, विशिष्ट मूल्य महत्वपूर्ण नहीं होता है। इस तरह के रूप में tunables के लिए मामला जैसे है BORDER_WIDTH = 2या TIMEOUT = 60; // secondsया टेम्पलेट्स जैसे API_ENDPOINT = "https://api.example.com/v2/"- हालांकि यकीनन कुछ या उन सभी कोड विन्यास फाइल के बजाय में निर्दिष्ट किया जाना चाहिए।


5
मुझे यह विश्लेषण पसंद है। मैं इसे इस रूप में पढ़ता हूं: आप एक निरंतर परिवर्तन करने के लिए स्वतंत्र हैं जब तक आप समझते हैं कि इसका उपयोग कैसे किया जाता है।
कैंडिड_ऑरेंज

सार्वजनिक मुद्दों के साथ +1 C # भी इसी मुद्दे से "ग्रस्त" है।
Reginald Blue

6

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

  • लगातार आवेदन स्थान लेते हैं
  • संकलक झंडे नहीं
  • स्थिरांक द्वारा बंद कोड को आधुनिक रीफैक्टरिंग उपकरणों के साथ अद्यतन और बदला जा सकता है
  • संकलक झंडे द्वारा बंद कोड नहीं कर सकते

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

मैं कह रहा हूं कि यह प्रदर्शित करने के लिए कि व्यापार बंद हैं। कुछ बूलियनों का वजन स्मृति से बाहर चलाने या बहुत अधिक स्थान लेने के लिए नहीं जा रहा था। यह सच नहीं हो सकता है यदि आपका स्थिरांक वास्तव में एक बड़ी वस्तु है जो अनिवार्य रूप से आपके कोड में सब कुछ संभालती है। यदि किसी वस्तु को रखने की आवश्यकता नहीं है, तो यह ध्यान नहीं रखता है कि यह अब जरूरी नहीं है, तो आपकी वस्तु स्मृति रिसाव का स्रोत हो सकती है।

आपको उपयोग के मामले का मूल्यांकन करने की आवश्यकता है और आप स्थिरांक को क्यों बदलना चाहते हैं।

मैं साधारण कंबल बयानों का प्रशंसक नहीं हूं, लेकिन सामान्य तौर पर आपका वरिष्ठ सहयोगी सही है। यदि कोई चीज अक्सर बदलने के लिए बाध्य होती है, तो उसे एक कॉन्फ़िगर करने योग्य आइटम होने की आवश्यकता हो सकती है। उदाहरण के लिए, आप शायद अपने सहकर्मी को निरंतर के लिए मना सकते हैं IsInDebugMode = trueजब आप कुछ कोड को टूटने से बचाना चाहते हैं। हालाँकि, कुछ चीज़ों को आपके द्वारा कोई एप्लिकेशन जारी करने से अधिक बार बदलने की आवश्यकता हो सकती है। यदि ऐसा है, तो आपको उचित समय पर उस मूल्य को बदलने का एक तरीका चाहिए। आप एक का उदाहरण ले सकते हैं TaxRate = .065। यह उस समय सही हो सकता है जब आप अपना कोड संकलित करते हैं, लेकिन नए कानूनों के कारण यह आपके आवेदन के अगले संस्करण को जारी करने से पहले बदल सकता है। यह ऐसी चीज़ है जिसे कुछ संग्रहण तंत्र (जैसे फ़ाइल या डेटाबेस) से अद्यतन करने की आवश्यकता है


आप "संकलक झंडे" से क्या मतलब है? शायद सी प्रीप्रोसेसर और समान कंपाइलर विशेषताएं जो मैक्रोज़ / डिफाइन और #ifdefएस का समर्थन करती हैं ? चूंकि ये स्रोत कोड के पाठ प्रतिस्थापन पर आधारित हैं , वे प्रोग्रामिंग भाषा शब्दार्थ का हिस्सा नहीं हैं। ध्यान दें कि जावा में प्रीप्रोसेसर नहीं है।
आमोन

@amon, Java नहीं हो सकता है, लेकिन कई भाषाएं करती हैं। मेरा मतलब है #ifdefझंडे। जबकि वे C के शब्दार्थ का हिस्सा नहीं हैं, वे C # का हिस्सा हैं। मैं भाषा अज्ञेयवाद के बड़े संदर्भ के लिए लिख रहा था।
बेरिन लोरिट्श

मुझे लगता है कि "मेमोरी वेस्ट" तर्क लूट है। इन-लाइनिंग और ट्री शेकिंग किसी भी रिलीज़-मोड ऑप्टिमाइज़र में एक बहुत अधिक सार्वभौमिक कदम है।
अलेक्जेंडर - मोनिका

@Alexander, मैं सहमत हूँ। यह हालांकि जागरूक होने के लिए कुछ है।
बेरिन लोरिट्श

1
"स्थिरांक अनुप्रयोग स्थान लेते हैं" - जब तक आप केवल एक किलोबाइट या दो मेमोरी के साथ एक माइक्रोकंट्रोलर के लिए एक एम्बेडेड एप्लिकेशन विकसित कर रहे हैं, आपको ऐसी चीजों के बारे में सोचना भी नहीं चाहिए।
vsz

2

const, #defineया finalएक संकलक संकेत (ध्यान दें कि है #defineवास्तव में एक संकेत नहीं है, इसकी एक मैक्रो और काफी अधिक शक्तिशाली)। यह इंगित करता है कि एक कार्यक्रम के निष्पादन पर मूल्य नहीं बदलेगा और विभिन्न अनुकूलन किए जा सकते हैं।

हालांकि, एक कंपाइलर संकेत के रूप में, कंपाइलर उन चीजों को करता है जो प्रोग्रामर द्वारा हमेशा अपेक्षित नहीं हो सकते हैं। विशेष रूप से, javac इनलाइन करेगा static final int FOO = 42;ताकि कहीं भी FOOइस्तेमाल होने वाले वास्तविक संकलित बाइट कोड को पढ़ा जा सके 42

यह तब तक बहुत ज्यादा आश्चर्य की बात नहीं है जब तक कि कोई अन्य संकलन इकाई (.java फ़ाइल) को फिर से 42देखे बिना मूल्य नहीं बदलता है - और बाइट कोड में अवशेष (देखें कि स्थिर अंतिम चर की javac की इनलाइनिंग को अक्षम करना संभव है? )।

कुछ बनाने का static finalमतलब है कि यह वह है और हमेशा के लिए अधिक हो जाएगा और इसे बदलना एक बहुत बड़ी बात है - खासकर अगर कुछ भी लेकिन private

चीजों के लिए निरंतरता final static int ZERO = 0एक समस्या नहीं है। final static double TAX_RATE = 0.55(पैसे और डबल होने से एक तरफ खराब है और बिगडेसीमल का उपयोग करना चाहिए, लेकिन फिर इसका एक आदिम नहीं है और इस तरह से इनलेट नहीं है) एक समस्या है और जहां इसका उपयोग किया जाता है, इसकी बहुत सावधानी से जांच की जानी चाहिए।


शून्य के छोटे मूल्यों के लिए।

3
is a problem and should be examined with great care for where it is used.यह एक समस्या क्यों है?
अलेक्जेंडर - मोनिका

1

जैसा कि नाम से पता चलता है, स्थिरांक को रनटाइम के दौरान नहीं बदलना चाहिए और मेरी राय में स्थिरांक को दीर्घकालिक के लिए नहीं बदलने के लिए परिभाषित किया गया है (आप अधिक जानकारी के लिए इस SO प्रश्न को देख सकते हैं।

जब यह झंडे की जरूरत की बात आती है (जैसे कि विकास मोड के लिए) तो आपको इस मोड को सक्षम करने के लिए एक कॉन्फ़िगर फ़ाइल या स्टार्टअप पैरामीटर (कई आईडीई समर्थन प्रति-प्रोजेक्ट-बेस पर स्टार्टअप पैरामीटर का संदर्भ लें) का उपयोग करना चाहिए; इस तरह से आप इस तरह के मोड का उपयोग करने के लिए लचीलापन बनाए रखते हैं और कोड को उत्पादक होने के कारण आप इसे बदलना नहीं भूल सकते।


0

रनों के बीच बदले जाने में सक्षम होना आपके स्रोत कोड में एक स्थिरांक को परिभाषित करने के सबसे महत्वपूर्ण बिंदुओं में से एक है!

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

एक प्रतिकूल उदाहरण के रूप में: यह समझ में नहीं आता है कि एक निरंतर है TRUEजो trueएक ऐसी भाषा में विकसित होता है जिसमें वास्तव में trueकीवर्ड है। आप कभी भी, कभी नहीं, एक बार भी, TRUE=falseएक क्रूर मजाक को छोड़कर घोषित नहीं करेंगे।

बेशक, स्थिरांक के अन्य उपयोग हैं, उदाहरण के लिए कोड को छोटा करना ( CO_NAME = 'My Great World Unique ACME Company'), दोहराव से बचना ( PI=3.141), सम्मेलनों ( TRUE=1) या जो भी हो, लेकिन स्थिरांक को बदलने के लिए एक परिभाषित स्थिति होना निश्चित रूप से सबसे प्रमुख लोगों में से एक है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.