क्या आवश्यक विधि मापदंडों के लिए Assert या IllegalArgumentException का उपयोग करना बेहतर है?


87

जावा में, जो अधिक अनुशंसित है, और क्यों? दोनों प्रकार अपवाद छोड़ देंगे, इसलिए इस संबंध में उन्हें संभालना एक समान है। assertथोड़ा कम है, लेकिन मुझे यकीन नहीं है कि यह कितना मायने रखता है।

public void doStuff(Object obj) {
    assert obj != null;
    ...
}

बनाम

public void doStuff(Object obj) {
    if (obj == null) {
        throw new IllegalArgumentException("object was null");
    }
    ...
}

मैं obj.hashCode()इसके बजाय एक सरल पसंद करता हूं ;-)
मार्को

जवाबों:


117

सावधान!

जब तक आप स्पष्ट रूप से अपने कोड को संकलित करने के लिए "जोर देने के लिए" निर्दिष्ट नहीं करते हैं, तब तक रनटाइम पर दावे हटा दिए जाते हैं। जावा अभिकथन का उपयोग उत्पादन कोड पर नहीं किया जाना चाहिए और इसे निजी विधियों ( अपवाद बनाम अभिकथन देखें ) तक सीमित रखा जाना चाहिए , क्योंकि निजी तरीकों को केवल डेवलपर्स द्वारा ही जाना और उपयोग किया जाना अपेक्षित है। साथ assertही जोर-जोर से जोर लगाएगा जो कि विस्तारित Errorनहीं होता है Exception, और जो सामान्य रूप से इंगित करता है कि आपके पास एक बहुत ही असामान्य त्रुटि है (जैसे "आउटऑफमेरीऑरर" जो कि इससे उबरना मुश्किल है, क्या यह नहीं है?) आपको इलाज करने में सक्षम होने की उम्मीद नहीं है।

"सक्षम करें" ध्वज निकालें, और डीबगर के साथ जांचें और आप देखेंगे कि आप IllegalArgumentException थ्रो कॉल पर कदम नहीं उठाएंगे ... क्योंकि इस कोड को संकलित नहीं किया गया है (फिर से, जब "ea" हटा दिया जाता है)

सार्वजनिक / संरक्षित विधियों के लिए दूसरे निर्माण का उपयोग करना बेहतर है, और यदि आप कुछ ऐसा चाहते हैं जो कोड की एक पंक्ति में किया जाता है, तो कम से कम एक तरीका है जो मुझे पता है। मैं व्यक्तिगत रूप से उपयोग करें स्प्रिंग फ्रेमवर्क के Assertवर्ग तर्क और विफलता पर कि फेंक "IllegalArgumentException" जाँच के लिए कुछ तरीकों है। मूल रूप से, आप क्या करते हैं:

Assert.notNull(obj, "object was null");

... जो वास्तव में उसी कोड को निष्पादित करेगा जो आपने अपने दूसरे उदाहरण में लिखा था। कुछ अन्य उपयोगी तरीके हैं hasText, जैसे कि hasLengthवहाँ।

मुझे आवश्यकता से अधिक कोड लिखना पसंद नहीं है, इसलिए जब मैं लिखित पंक्तियों की संख्या को 2 (2 पंक्तियों> 1 पंक्ति) से कम कर खुश हूँ तो :-)


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

2
ध्यान दें कि कोई ध्वज नहीं है जो संकलन समय पर जोर को हटा देता है (हालांकि उन्हें सशर्त संकलन के माध्यम से हटाया जा सकता है )। डिफ़ॉल्ट रूप से दावे रनटाइम पर अक्षम होते हैं (मुझे लगता है कि JVM उन्हें NOOP के रूप में मानता है), लेकिन java -eaप्रोग्राम के माध्यम से और सक्षम किया जा सकता है। @ जलयान मुझे लगता है कि उत्पादन कोड में दावे पूरी तरह से मान्य हैं, क्योंकि वे क्षेत्र में डिबगिंग के
जस्टिन मुलर

@ जालयान, -1। कंपाइलर अभिकथन कोड को नहीं हटाता है। जब तक आप cmd नहीं करेंगे तब भी वे नहीं चलेंगे java -ea
पचेरियर

5
जब आप उपयोग कर सकते हैं तो स्प्रिंग फ्रेमवर्क की कोई आवश्यकता नहीं हैObjects.requreNonNull
कैमब्यूटियस

46

आपको एक अपवाद का उपयोग करने की आवश्यकता है। अभिकथन का उपयोग करना सुविधा का दुरुपयोग होगा।

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

उदाहरण के लिए, एक जोर

assert myConnection.isConnected();

इसका अर्थ है "मुझे पता है कि इस अभिकथन के लिए जाने वाला प्रत्येक कोड पथ myConnectionजुड़ा हुआ है जो सुनिश्चित करता है ; यदि ऊपर वाला कोड वैध कनेक्शन प्राप्त करने में विफल रहा है, तो उसे इस बिंदु पर पहुंचने से पहले अपवाद या रिटर्न को फेंक देना चाहिए।"

दूसरी ओर, एक चेक

if (!myConnection.isConnected()) {
    throw new IllegalArgumentException("connection is not established");
}

इसका मतलब है कि "कनेक्शन स्थापित किए बिना मेरे पुस्तकालय को कॉल करना एक प्रोग्रामिंग त्रुटि है"।


1
यह जानकारी वास्तव में मददगार है, लेकिन मैं जलयान को स्वीकार कर रहा हूं क्योंकि यह बताता है कि कैसे मैं संभावित रूप से मुखर विधि के साथ बग को पेश कर सकता हूं।
डेनिथ

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

सच है, लेकिन यह मानता है कि ओपी एक पुस्तकालय लिख रहा है। यदि उनका कोड सिर्फ आंतरिक उपयोग के लिए है तो एक स्वीकार्य है।
user949300

11

यदि आप एक फ़ंक्शन लिख रहे हैं nullजो मान्य पैरामीटर मान के रूप में अनुमति नहीं देता है , तो आपको @Nonnullहस्ताक्षर में एनोटेशन जोड़ना चाहिए और Objects.requireNonNullयह जांचने के लिए उपयोग करना चाहिए कि क्या तर्क है nullऔर NullPointerExceptionयदि है तो फेंक दें । @Nonnullएनोटेशन प्रलेखन के लिए है और कुछ मामलों में संकलन समय पर उपयोगी चेतावनी प्रदान करेगा। यह nullरनटाइम पर पास होने से नहीं रोकता है।

void doStuff(@Nonnull Object obj) {
    Objects.requireNonNull(obj, "obj must not be null");

    // do stuff...
}

अपडेट करें:@Nonnull एनोटेशन जावा मानक पुस्तकालय का हिस्सा नहीं है। इसके बजाय, तीसरे पक्ष के पुस्तकालयों से कई प्रतिस्पर्धी मानक हैं (देखें कि कौन सा @NotNull जावा एनोटेशन मुझे उपयोग करना चाहिए? )। इसका मतलब यह नहीं है कि इसका उपयोग करने के लिए एक बुरा विचार है, बस यह मानक नहीं है।


इशारा करने के लिए धन्यवाद Objects.requireNonNull(), जो मेरे लिए नया था। क्या आपको पता है कि कहीं भी इसी तरह की "रिक्वायरमेंट ()" या "रिक्वायरमेंट ()" की विधि है? स्प्रिंग एसर के खिलाफ कुछ भी नहीं, लेकिन हर कोई इसका उपयोग नहीं कर रहा है।
user949300

@ user949300 Objects.requireNonNull()तर्क सत्यापन के लिए है। यदि किसी तर्क trueको किसी चीज़ के बराबर या उसके बराबर होना आवश्यक है, तो तर्क व्यर्थ है। अवैध तर्क के अलावा अन्य त्रुटि मामलों के लिए, आप चाहिए throwएक Exceptionऔर अधिक सही त्रुटि का वर्णन करता है। वहाँ भी JUnit है, Assertलेकिन यह परीक्षण के लिए है।
ऊंट

मैं और अधिक की तरह सोच रहा था, एक वर्गमूल समारोह के लिए कहें Objects.requireTrue(x >= 0.0);, या कुछ हैश के लिए,Objects.requireEquals(hash.length == 256)
user949300

कौन सा @ नोनल मुझे उपयोग करना है? javax.validation.constraints.NotNull?
अगुविद

मैं ग्रहण JDT एनोटेशन का उपयोग करूंगा , क्योंकि वे चतुर लोगों द्वारा बनाए गए हैं :)। प्रलेखन: help.eclipse.org/neon/… - आप इनका उपयोग करने के लिए IntelliJ को भी कॉन्फ़िगर कर सकते हैं।
21

2

मैं हमेशा से ही गैरकानूनी धारणा को उखाड़ फेंकना पसंद करता हूं।

परीक्षण परिणामों को जांचने / परखने के लिए, ज्यादातर का उपयोग JUnit या अन्य परीक्षण उपकरणों में किया जाता है। तो यह अन्य डेवलपर्स को गलत धारणा दे सकता है कि आपका तरीका एक परीक्षण विधि है।

यह भी अवैध तरीके से गैरकानूनी या अनुचित तर्क पारित किए जाने पर IllegalArgumentException को फेंकने के लिए समझ में आता है । यह जावा डेवलपर्स द्वारा पीछा अपवाद हैंडलिंग सम्मेलन के साथ अधिक सुसंगत है।


5
JUnit से लगभग 40 साल पहले दावे थे - ASSERT मैक्रोज़ के बारे में C प्रोग्रामर से पूछें।
JBRWilkinson

3
यह प्रश्न c के बारे में नहीं है; इसके बारे में जावा। इसलिए मैंने जावा के संदर्भ में उत्तर दिया है।
राय.कुमार

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

1

IMO दूसरा बेहतर है क्योंकि यह अधिक जानकारी लाता है और इसे और अधिक विस्तारित किया जा सकता है (जैसे अपवाद वर्ग का विस्तार करके) और भी अधिक जानकारीपूर्ण होने के लिए, यह भी नकारात्मक तुलना का उपयोग नहीं करता है जो समझना आसान है।


1

मैं लोम्बॉक @NonNull के साथ बहुत सारे, लेकिन आम दृष्टिकोण का उपयोग नहीं करता: https://projectlombok.org/features/NonNull

लोम्बोक कार्यान्वयन: आयात lombok.NonNull;

public class NonNullExample extends Something {
  private String name;

  public NonNullExample(@NonNull Person person) {
    super("Hello");
    this.name = person.getName();
  }
}

जावा संस्करण:

 import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;

  public NonNullExample(@NonNull Person person) {
    super("Hello");
    if (person == null) {
      throw new NullPointerException("person");
    }
    this.name = person.getName();
  }
}

लोम्बोक वास्तव में काफी अच्छा पुस्तकालय है जिसका उपयोग मैं हर जगह करता हूं

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