क्या आपको उत्पादन कोड में मुखर कथन के साथ अशक्त नहीं होना चाहिए? [बन्द है]


32

मैंने यह प्रश्न देखा है, लेकिन assertकीवर्ड के उपयोग के बारे में कुछ और प्रश्न हैं । मैं उपयोग करने के बारे में कुछ अन्य कोडर के साथ बहस कर रहा था assert। इस उपयोग के मामले में, एक ऐसी विधि थी जो कुछ शर्तो को पूरा करने पर अशक्त हो सकती है। मेरे द्वारा लिखा गया कोड विधि को कॉल करता है, फिर दावा करता है कि यह अशक्त नहीं है, और लौटे ऑब्जेक्ट का उपयोग करना जारी रखता है।

उदाहरण:

class CustomObject {
    private Object object;

    @Nullable
    public Object getObject() {
        return (object == null) ? generateObject() : object;
    }
}

अब कल्पना करें कि मैं इसका उपयोग इस तरह करता हूं:

public void useObject(CustomObject customObject) {
    object = customObject.getObject();
    assert object != null;
    // Do stuff using object, which would throw a NPE if object is null.
}

मुझे बताया गया कि मुझे हटा देना चाहिए assert, कि उन्हें कभी भी उत्पादन कोड में उपयोग नहीं किया जाना चाहिए , केवल परीक्षण में उपयोग किया जाना चाहिए। क्या यह सच है?


19
डिफ़ॉल्ट रूप से, दावे अक्षम हैं। आपको उन्हें रनटाइम के माध्यम से -eaया समकक्ष स्पष्ट रूप से सक्षम करना होगा ।
जरमोद

सॉफ्टवेयर इंजीनियरिंग पर संबंधित प्रश्न: softwareengineering.stackexchange.com/q/137158/187318 (हालांकि यह काफी पुराना है, इसलिए वहां स्वीकार किए गए उत्तर अभी भी एक बाहरी पुस्तकालय की सलाह देते हैं, जो अब Objects.requireNonNullजावा 8 के आने के बाद से आवश्यक नहीं है )।
हल्क

यह प्रश्न शीर्षक अधिक व्यापक है, लेकिन शरीर में बताया गया प्रश्न बहुत अधिक संकीर्ण है, और उत्तर के अनुसार पूरी तरह से सहायक कार्यों द्वारा नियंत्रित किया जाता है।
मुस्कान

स्पष्ट होने के लिए, आप पूछ रहे हैं कि क्या ग्राहक कोड को वस्तुओं पर गैर-शून्य जांच / जोर लगाना चाहिए। (यह पूछने से अलग है कि क्या लाइब्रेरी कोड को ही वस्तुओं की गारंटी चाहिए या नहीं, या यह दावा नहीं किया जा सकता है)।
मुस्कान

जवाबों:


19

उसके लिए उपयोग करें Objects.requireNonNull(Object)

जाँचता है कि निर्दिष्ट वस्तु संदर्भ शून्य नहीं है। यह विधि मुख्य रूप से विधियों और निर्माणकर्ताओं में पैरामीटर सत्यापन करने के लिए डिज़ाइन की गई है, [...]

आपके मामले में यह होगा:

public void useObject(CustomObject customObject) {
    object = customObject.getObject();
    Objects.requireNonNull(object);
    // Do stuff using object, which would throw a NPE if object is null.
}

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

एक अन्य लाभ इसके विपरीत अशक्त जांच के बारे में अतिरिक्त लचीलापन है assert। जबकि assertएक बूलियन मान की जाँच करने के लिए एक कीवर्ड है, Objects.requireNonNull(Object)एक फ़ंक्शन है और इस प्रकार कोड में अधिक लचीला और पठनीय में एम्बेड किया जा सकता है। उदाहरण के लिए:

Foo foo = Objects.requireNonNull(service.fetchFoo());

// You cannot write it in on line.
Bar bar = service.fetchBar();
assert bar != null;
service.foo(Objects.requireNonNull(service.getBar()));

// You cannot write it in on line.
Bar bar = service.getBar();
assert bar != null;
service.foo(bar);

ध्यान रखें कि Objects.requireNonNull(Object)विशेष रूप से अशक्त जाँच के लिए जहाँ assertसामान्यीकृत है। assertउस संबंध में थोड़ा अलग उद्देश्य हैं, अर्थात मुख्य रूप से परीक्षण। इसे सक्षम करना है, इसलिए आप इसे परीक्षण के लिए सक्षम कर सकते हैं और इसे उत्पादन के लिए अक्षम कर सकते हैं। वैसे भी, यह उत्पादन कोड के लिए उपयोग नहीं करते हैं। यह अनावश्यक और जटिल मान्यताओं के साथ आवेदन को धीमा कर सकता है जो परीक्षण के लिए हैं। इसका उपयोग केवल उन परीक्षणों से जांच को अलग करने के लिए करें जो उत्पादन के लिए भी हैं।

विवरण के लिए आधिकारिक दस्तावेज देखें assert


14
कौन और कब विरासत घोषित किया जाता है? कोई लिंक / संदर्भ? मैं किसी भी समझदार डेवलपर को "विरासत" को परिभाषित करने की कल्पना नहीं कर सकता हूं जो शून्य-पदचिह्न सत्यापन को सक्षम करने वाला उपकरण है जो आसानी से परीक्षणों में सक्षम हो सकता है और उत्पादन में अक्षम हो सकता है।
दिमित्री पिस्कलोव

यह देखते हुए कि आप रनटाइम पर निर्णय ले सकते हैं कि क्या मुखर संचालित होता है, लेकिन आप रनटाइम पर यह निर्धारित नहीं कर सकते हैं कि क्या एनपीई को आवश्यकता के अनुसार फेंक दिया गया है, तो आपको क्या मतलब है कि 'आपके पास इसके साथ अधिक नियंत्रण है'?
पीट किर्कम

@DmitryPisklov आप सही हैं, मैंने इसे संपादित किया है। यह परीक्षण के लिए एक महान उपकरण है।
अकुज़मिन्यख

2
@PeteKirkham आप सही हैं, नियंत्रण उसके लिए गलत शब्द था। मैं सिंटैक्स में लचीलेपन के बारे में अधिक बात कर रहा था। इसके अलावा: यहां ऐसे कारण मिल सकते हैं कि आप एनपीई को फेंकने के लिए कोड क्यों चाहते हैं।
अकुज़मिन्यख

1
"इसे उत्पादन कोड के लिए उपयोग न करें। यह एप्लिकेशन को धीमा कर सकता है" यह हो सकता है, लेकिन यह इसके लायक हो सकता है। जावा ने यह सुनिश्चित करने के लिए रन-इन चेक का निर्माण किया है कि आप किसी सरणी से आगे नहीं बढ़ें। संभावित प्रदर्शन जुर्माना के बावजूद, उत्पादन तैनाती पर भी ये सक्षम हैं। हमें इसके बारे में कोई विकल्प नहीं दिया गया है। प्रोडक्शन कोड में रनटाइम चेक करना हमेशा गलत नहीं होता।
मैक्स बैरक्लोफ़

22

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

पिछड़ी संगतता के लिए, JVM डिफ़ॉल्ट रूप से अभिकथन सत्यापन अक्षम करता है। उन्हें -enableaseries कमांड लाइन तर्क, या इसके शॉर्टहैंड -ea का उपयोग करके स्पष्ट रूप से सक्षम होना चाहिए:

java -ea com.whatever.assertion.Assertion

इसलिए, उन पर भरोसा करना एक अच्छा अभ्यास नहीं है।

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


स्पष्ट रूप से उन पर भरोसा करने के लिए बुरा अभ्यास, लेकिन क्या सामान्य रूप से इसका उपयोग करना बुरा अभ्यास है?
Big_Bad_E

3
@Big_Bad_E अभिकथन एक डिबग टूल है जो किसी प्रोग्राम को जल्द से जल्द और यथाशीघ्र विफल करने के लिए मौजूद है। यह परीक्षण सूट का काम है ताकि यह सुनिश्चित किया जा सके कि किसी भी तरह से कोई कार्यक्रम जोर-शोर से विफल हो सकता है । यह विचार है, एक बार परीक्षण सूट (यह 100% कवरेज मिला है, है ना??) बिना किसी विफलता के निष्पादित करता है, यह अभिकथन को हटाने के लिए बचा है क्योंकि वे वैसे भी ट्रिगर नहीं कर सकते हैं। यकीन है कि इस तर्क में थोड़ा आदर्शवाद है, लेकिन यह विचार है।
सेंटास्टर -

11

निश्चित रूप से आपको जो बताया जाता है वह एक झूठ है। यहाँ पर क्यों।

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

उस ने कहा, जैसा कि अन्य उत्तर से पता चलता है, ठीक उसी कारण से (वे हमेशा सक्षम नहीं हैं) आप कुछ महत्वपूर्ण जांच करने के लिए जोर पर भरोसा नहीं कर सकते हैं, या (विशेष रूप से!) किसी भी राज्य को बनाए रखते हैं।

आप कैसे इस्तेमाल कर सकते हैं का एक दिलचस्प उदाहरण का दावा है के लिए, एक नजर है यहाँ - वहाँ एक विधि है फ़ाइल के अंत में singleThreadedAccess()जो लाइन 201 पर ज़ोर बयान से फोन किया और टेस्ट मैचों में किसी भी संभावित बहु पहुँच को पकड़ने के लिए है।


4

अन्य उत्तर पहले से ही इसे अच्छी तरह से कवर करते हैं, लेकिन अन्य विकल्प भी हैं।

उदाहरण के लिए, स्प्रिंग में एक स्थिर विधि है:

org.springframework.util.Assert.notNull(obj)

अपने स्वयं के Assert.something()तरीकों के साथ अन्य पुस्तकालय भी हैं। अपना खुद का लिखना भी बहुत आसान है।

हालाँकि, ध्यान रखें कि यदि आप एक वेब सेवा है तो आप कौन से अपवादों को फेंकते हैं। उदाहरण के लिए, पिछली विधि, IllegalArgumentExceptionजो स्प्रिंग में डिफ़ॉल्ट रूप से 500 का रिटर्न देती है , फेंकती है ।

एक वेब सेवा के मामले में, यह अक्सर है नहीं कोई आंतरिक सर्वर त्रुटि है, और एक 500 नहीं होना चाहिए, बल्कि एक 400 है, जो एक बुरा अनुरोध है।


1
यदि "Assert" विधि प्रक्रिया को तुरंत क्रैश नहीं करती है, इसके बजाय किसी प्रकार का अपवाद फेंकती है, तो यह एक जोर नहीं है। संपूर्ण बिंदु assertयह है कि उत्पादित कोर फाइल के साथ तत्काल दुर्घटना हो जाए, ताकि आप अपने पसंदीदा डिबगर के साथ उस स्थान पर सही तरीके से पोस्टमार्टम कर सकें जहां स्थिति का उल्लंघन किया गया था।
सेंटास्टर -

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

आह, जावा वास्तव assertमें फेंक करने के लिए परिभाषित करता है । दिलचस्प। C / C ++ संस्करण ऐसा काम नहीं करता है। यह तुरंत एक संकेत उठाता है कि ए) प्रक्रिया को मारता है, और बी) एक कोर डंप बनाता है। यह एक कारण के लिए ऐसा करता है: यह इस तरह की जोरदार विफलता को डीबग करने के लिए मृत है क्योंकि आपके पास अभी भी उपलब्ध कॉल स्टैक के बारे में पूरी जानकारी है। assertइसके बजाय एक अपवाद को फेंकने के लिए परिभाषित करना , जो तब (अन) जानबूझकर प्रोग्रामिक रूप से पकड़ा जा सकता है, उद्देश्य को हरा सकता है, इम्हो।
cmaster - मोनिका

जिस तरह C और C ++ में कुछ (या कई) अजीब चीजें हैं, वहीं जावा में कुछ हैं। उनमें से एक है Throwable। वे हमेशा पकड़े जा सकते हैं। अच्छी बात है या नहीं, मुझे नहीं पता। मुझे लगता है कि यह निर्भर करता है। कई जावा प्रोग्राम वेब सेवाएँ हैं, और लगभग किसी भी कारण से दुर्घटनाग्रस्त होना अवांछनीय होगा, इसलिए बस के बारे में सब कुछ पकड़ा और लॉग इन किया जाता है। महान चीजों में से एक स्टैक ट्रेस है, और यह आमतौर पर अपवाद या त्रुटि के कारण का निदान करने के लिए पर्याप्त है।
क्रिस्टोफर श्नाइडर

3

जब भी ऐसा हो, उदारतापूर्वक उपयोग की जाने वाली प्रोग्रामिंग गलतियों को पकड़ने में मदद करें ।

तार्किक रूप से घटित इनपुट के तार्किक रूप से होने वाली किसी चीज़ को पकड़ने के लिए मुखर का उपयोग न करें। त्रुटि के अपरिवर्तनीय होने पर ही जोर का प्रयोग करें।

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

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

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


2

आप किसी भी समय मुखर का उपयोग कर सकते हैं। बहस तब होती है जब उपयोग करना है। उदाहरण के लिए गाइड में :

  • सार्वजनिक तरीकों से तर्क की जाँच के लिए जोर का प्रयोग न करें।
  • किसी भी कार्य को करने के लिए जो आपके आवेदन को सही संचालन के लिए आवश्यक है, का उपयोग न करें।

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