नियंत्रण के नियमित प्रवाह के रूप में अपवादों का उपयोग क्यों नहीं किया जाता है?


192

सभी मानक-उत्तरों से बचने के लिए मैं Googled पर चल सकता हूं, मैं एक उदाहरण प्रदान करूंगा जो आप सभी पर हमला कर सकते हैं।

C # और Java (और बहुत से अन्य) में बहुत सारे प्रकार के कुछ 'अतिप्रवाह' व्यवहार हैं जो मुझे बिल्कुल पसंद नहीं हैं (उदाहरण type.MaxValue + type.SmallestValue == type.MinValueके लिए int.MaxValue + 1 == int.MinValue)।

लेकिन, मेरे शातिर स्वभाव को देखते हुए, मैं इस व्यवहार का विस्तार करके इस चोट के लिए कुछ अपमान जोड़ूंगा, चलो एक ओवरराइड DateTimeप्रकार कहते हैं । (मैं जानता हूँ कि DateTimeनेट में बंद है, लेकिन इस उदाहरण के लिए, मैं एक छद्म भाषा है कि वास्तव में सी # की तरह है, तथ्य यह है कि दिनांक समय सील नहीं किया गया है के अलावा उपयोग कर रहा हूँ)।

ओवरराइड Addविधि:

/// <summary>
/// Increments this date with a timespan, but loops when
/// the maximum value for datetime is exceeded.
/// </summary>
/// <param name="ts">The timespan to (try to) add</param>
/// <returns>The Date, incremented with the given timespan. 
/// If DateTime.MaxValue is exceeded, the sum wil 'overflow' and 
/// continue from DateTime.MinValue. 
/// </returns>
public DateTime override Add(TimeSpan ts) 
{
    try
    {                
        return base.Add(ts);
    }
    catch (ArgumentOutOfRangeException nb)
    {
        // calculate how much the MaxValue is exceeded
        // regular program flow
        TimeSpan saldo = ts - (base.MaxValue - this);
        return DateTime.MinValue.Add(saldo)                         
    }
    catch(Exception anyOther) 
    {
        // 'real' exception handling.
    }
}

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

मुझे लगता है कि कई मामलों में वे अगर संरचनाओं की तुलना में अधिक स्पष्ट हैं और विधि बनाने वाले किसी भी अनुबंध को नहीं तोड़ते हैं।

IMHO "कभी भी नियमित कार्यक्रम प्रवाह के लिए उनका उपयोग न करें" प्रतिक्रिया हर किसी को लगती है कि यह अच्छी तरह से रेखांकित नहीं है क्योंकि उस प्रतिक्रिया की ताकत न्यायोचित हो सकती है।

या मैं गलत हूँ?

मैंने अन्य पदों को पढ़ा है, सभी प्रकार के विशेष मामलों से संबंधित है, लेकिन मेरी बात यह है कि यदि आप दोनों हैं तो इसमें कुछ भी गलत नहीं है:

  1. स्पष्ट
  2. अपने तरीके के अनुबंध का सम्मान करें

मुझे गोली मारो।


2
+1 मैं उसी तरह महसूस करता हूं। प्रदर्शन के अलावा, अपवाद-से-नियंत्रण-प्रवाह से बचने का एकमात्र अच्छा कारण यह है कि कॉलर कोड रिटर्न मानों के साथ अधिक पठनीय होगा।

4
है: वापसी -1 अगर कुछ हुआ, तो वापसी -2 अगर कुछ और, आदि ... वास्तव में अधिक पठनीय है तो अपवाद?
kender

1
यह दुखद है कि किसी को सच बताने के लिए नकारात्मक प्रतिष्ठा मिलती है: यदि आपके उदाहरण को बयानों के साथ नहीं लिखा जा सकता है। (यह कहना सही नहीं है / पूर्ण है।)
इंगो

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

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

जवाबों:


169

क्या आपने कभी किसी कार्यक्रम को संचालन के सामान्य पाठ्यक्रम में प्रति सेकंड पांच अपवादों को बढ़ाने की कोशिश की है?

मेरे पास है।

कार्यक्रम काफी जटिल था (यह एक वितरित गणना सर्वर था), और कार्यक्रम के एक तरफ एक मामूली संशोधन पूरी तरह से अलग जगह में आसानी से कुछ तोड़ सकता है।

काश मैं सिर्फ कार्यक्रम लॉन्च कर पाता और अपवादों के होने का इंतजार कर सकता था, लेकिन ऑपरेशन के सामान्य पाठ्यक्रम में स्टार्ट-अप के दौरान लगभग 200 अपवाद थे

मेरी बात: यदि आप सामान्य स्थितियों के अपवादों का उपयोग करते हैं, तो आप असामान्य (यानी अपवाद अल) स्थितियों का पता कैसे लगाते हैं ?

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


13
उदाहरण: जब मैं एक .net प्रोग्राम डिबग करता हूं, तो मैं इसे विजुअल स्टूडियो से लॉन्च करता हूं और मैं वीएस से सभी अपवादों को तोड़ने के लिए कहता हूं। यदि आप अपवादों पर एक अपेक्षित व्यवहार के रूप में भरोसा करते हैं, तो मैं अब ऐसा नहीं कर सकता (क्योंकि यह 5times / sec को तोड़ देगा), और कोड के समस्याग्रस्त भाग का पता लगाना कहीं अधिक जटिल है।
ब्रॉन

15
+1 इंगित करने के लिए कि आप वास्तविक असाधारण सुई खोजने के लिए एक अपवाद हैस्टैक नहीं बनाना चाहते हैं।
ग्रैन वैगनर

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

11
@ पेटर: अपवादों को तोड़े बिना डिबगिंग मुश्किल है, और सभी अपवादों को पकड़ना दर्दनाक होता है यदि उनमें से बहुत सारे डिज़ाइन के होते हैं। मुझे लगता है कि एक डिजाइन जो डिबगिंग को कठिन बनाता है, लगभग आंशिक रूप से टूट गया है (दूसरे शब्दों में, डिजाइन डीबगिंग, आईएमओ के साथ कुछ करना है)
ब्रैन

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

157

अपवाद gotoबाद के सभी परिणामों के साथ गैर-स्थानीय बयान हैं। प्रवाह नियंत्रण के अपवादों का उपयोग करना कम से कम विस्मय के सिद्धांत का उल्लंघन करता है , कार्यक्रमों को पढ़ने के लिए कठिन बनाएं (याद रखें कि प्रोग्राम पहले प्रोग्रामर के लिए लिखे गए हैं)।

इसके अलावा, यह वह नहीं है जो कंपाइलर विक्रेताओं को उम्मीद है। वे अपवादों को शायद ही कभी फेंकने की उम्मीद करते हैं, और वे आमतौर पर throwकोड को काफी अक्षम होने देते हैं। अपवादों को फेंकना .NET में सबसे महंगे ऑपरेशनों में से एक है।

हालाँकि, कुछ भाषाएं (विशेषकर पायथन) अपवादों का उपयोग प्रवाह-नियंत्रण निर्माण के रूप में करती हैं। उदाहरण के लिए, StopIterationयदि कोई और आइटम नहीं हैं , तो पुनरावृत्तियाँ एक अपवाद को बढ़ाती हैं। यहां तक ​​कि मानक भाषा निर्माण (जैसे for) इस पर भरोसा करते हैं।


11
हे, अपवाद आश्चर्यजनक नहीं हैं! और जब आप कहते हैं कि आप "यह एक बुरा विचार है" का विरोध करते हैं और फिर कहने के लिए आगे बढ़ते हैं "लेकिन यह अजगर में एक अच्छा विचार है"।
hasen

6
मैं अभी भी बिल्कुल भी आश्वस्त नहीं हूं: 1) प्रयास प्रश्न के अलावा था, बहुत से गैर-बैच प्रोग्राम कम देखभाल नहीं कर सकते थे (जैसे यूजर इंटरफेस) 2) आश्चर्यजनक: जैसे मैंने कहा कि यह सिर्फ आश्चर्यजनक कारण है क्योंकि इसका उपयोग नहीं किया गया है, लेकिन सवाल यह है: पहली बार में आईडी का उपयोग क्यों नहीं? लेकिन, चूंकि इसका उत्तर है
पीटर

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

13
इसके विपरीत goto, निश्चित रूप से, अपवाद आपके कॉल स्टैक और लेक्सिकल स्कूपिंग के साथ सही ढंग से बातचीत करते हैं, और स्टैक या स्कोप्स को गड़बड़ाने में नहीं छोड़ते हैं।
लुकास एडर

4
दरअसल, अधिकांश वीएम विक्रेता अपवादों की अपेक्षा करते हैं, और उन्हें कुशलता से संभालते हैं। जैसा कि @LukasEder नोट अपवाद पूरी तरह से गोटो के विपरीत है कि वे संरचित हैं।
Marcin

29

अंगूठे का मेरा नियम है:

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

मैं अपवादों के साथ जो समस्या देख रहा हूं, वह विशुद्ध रूप से वाक्य-विन्यास से है (मुझे पूरा यकीन है कि परफ्यूम ओवरहेड न्यूनतम है)। मुझे पूरी जगह कोशिश-ब्लॉक पसंद नहीं है।

इस उदाहरण को लें:

try
{
   DoSomeMethod();  //Can throw Exception1
   DoSomeOtherMethod();  //Can throw Exception1 and Exception2
}
catch(Exception1)
{
   //Okay something messed up, but is it SomeMethod or SomeOtherMethod?
}

एक और उदाहरण तब हो सकता है जब आपको किसी कारखाने का उपयोग करके कुछ को सौंपने की आवश्यकता हो, और वह कारखाना एक अपवाद फेंक सकता है:

Class1 myInstance;
try
{
   myInstance = Class1Factory.Build();
}
catch(SomeException)
{
   // Couldn't instantiate class, do something else..
}
myInstance.BestMethodEver();   // Will throw a compile-time error, saying that myInstance is uninitalized, which it potentially is.. :(

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

आशा है कि मुझे आपका प्रश्न सही समझ में आया :)


4
पुन: आपका दूसरा उदाहरण - कॉल को ब्लॉक करने के बाद BestMethodEver को कॉल क्यों नहीं करना चाहिए? यदि बिल्ड () एक अपवाद फेंकता है, तो इसे निष्पादित नहीं किया जाएगा, और कंपाइलर खुश है।
Blorgbeard

2
हाँ, यह शायद वही होगा जो आप समाप्त करेंगे, लेकिन एक अधिक जटिल उदाहरण पर विचार करें जहां myInstance-type खुद अपवादों को फेंक सकता है .. और विधि के दायरे में अन्य भिन्नताएं भी हो सकती हैं। आप बहुत से नेस्टेड प्रयास / कैच ब्लॉक को समाप्त करेंगे :(
cwap

आपको अपने कैच ब्लॉक में एक्सेप्शन ट्रांसलेशन (एब्स्ट्रेक्शन के स्तर तक उपयुक्त अपवाद टाइप) करना चाहिए। FYI करें: "मल्टी-कैच" जावा 7 में होने वाला है
जेसोनेरोथिन

FYI करें: C ++ में, आप अलग-अलग अपवादों को पकड़ने की कोशिश के बाद कई कैच डाल सकते हैं।
रॉब

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

25

बहुत सारे उत्तरों की पहली प्रतिक्रिया:

आप प्रोग्रामर और कम से कम विस्मय के सिद्धांत के लिए लिख रहे हैं

बेशक! लेकिन अगर हर समय अधिक स्पष्ट नहीं है।

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

लेकिन उस मामले के लिए DivisionByZero और FileNotFound, if की तुलना में स्पष्ट हैं।

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

जहाँ तक कम से कम विस्मय का सिद्धांत है: यहाँ परिपत्र तर्क का खतरा है: मान लीजिए कि एक पूरा समुदाय खराब डिज़ाइन का उपयोग करता है, तो यह डिज़ाइन अपेक्षित हो जाएगा! इसलिए सिद्धांत एक कब्र नहीं हो सकता है और इसे ध्यान से समझना चाहिए।

सामान्य स्थितियों के अपवाद, आप असामान्य (असाधारण) स्थितियों का पता कैसे लगाते हैं?

कई प्रतिक्रियाओं में sth। इस तरह गर्त चमकता है। बस उन्हें पकड़ लो, नहीं? आपकी विधि स्पष्ट होनी चाहिए, अच्छी तरह से प्रलेखित होनी चाहिए, और यह अनुबंध है कि हाउनिंग करना। मुझे वह प्रश्न नहीं आता, जिसे मुझे मानना ​​चाहिए।

सभी अपवादों पर डिबगिंग: वही, बस कभी-कभी किया जाता है क्योंकि अपवादों का उपयोग नहीं करने का डिज़ाइन आम है। मेरा सवाल था: यह पहली जगह में क्यों आम है?


1
1) क्या आप हमेशा xकॉल करने से पहले जांच करते हैं 1/x? 2) क्या आप हर डिवीजन ऑपरेशन को पकड़ने के लिए एक कोशिश-पकड़ ब्लॉक में लपेटते हैं DivideByZeroException? 3) आप को पकड़ने के लिए किस तर्क को पकड़ में लाना चाहिए DivideByZeroException?
लाइटमैन

1
सिवाय DivisionByZero और FileNotFound के बुरे उदाहरण हैं क्योंकि वे असाधारण मामले हैं जिन्हें अपवाद के रूप में माना जाना चाहिए।
0x6C38

फ़ाइल के बारे में "अत्यधिक असाधारण" कुछ भी नहीं है, "विरोधी अपवाद" की तुलना में इस तरह से नहीं पाया गया है कि यहां के लोग टाल रहे हैं। openConfigFile();एक पकड़ा FileNotFound के साथ पालन किया जा सकता { createDefaultConfigFile(); setFirstAppRun(); }FileNotFound अपवाद के साथ इनायत से संभाला; कोई दुर्घटना नहीं, चलो अंत उपयोगकर्ता के अनुभव को बेहतर बनाते हैं, बदतर नहीं। आप कह सकते हैं "लेकिन क्या होगा अगर यह वास्तव में पहला रन नहीं था और वे हर बार प्राप्त करते हैं?" कम से कम ऐप हर बार चलता है और हर स्टार्टअप को क्रैश नहीं करता है! 1-टू -10 "यह भयानक है" पर: "पहला-रन" हर स्टार्टअप = 3 या 4, हर स्टार्टअप को क्रैश करता है = 10.
Loduwijk

आपके उदाहरण अपवाद हैं। नहीं, आप हमेशा xकॉल करने से पहले जांच नहीं करते हैं 1/x, क्योंकि यह आमतौर पर ठीक है। असाधारण मामला वह मामला है जहां यह ठीक नहीं है। हम यहां पृथ्वी-बिखरने की बात नहीं कर रहे हैं, लेकिन उदाहरण के लिए एक बेसिक पूर्णांक के लिए एक यादृच्छिक दिया x, 4294967296 में से केवल 1 विभाजन करने में विफल होगा। यह असाधारण है और अपवाद इससे निपटने का एक अच्छा तरीका है। हालाँकि, आप एक switchकथन के समकक्ष को लागू करने के लिए अपवादों का उपयोग कर सकते हैं , लेकिन यह बहुत मूर्खतापूर्ण होगा।
Thor84no

16

अपवादों से पहले, सी में, वहाँ थे setjmpऔर longjmpजिसका उपयोग स्टैक फ्रेम के एक समान अनरोलिंग को पूरा करने के लिए किया जा सकता था।

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

अपवाद थोड़े अधिक सामान्य हैं कि आप उन्हें एक ही स्टैक फ्रेम में भी उपयोग कर सकते हैं। यह इस बात के अनुरूप है gotoकि मैं गलत हूं। गॉटोस एक कसकर युग्मित जोड़ी हैं (और इसलिए हैं setjmpऔर longjmp)। अपवाद एक बहुत अच्छी तरह से प्रकाशित / सदस्यता है कि बहुत क्लीनर है सदस्यता लें! इसलिए उन्हें एक ही स्टैक फ्रेम के भीतर उपयोग करना शायद ही gotoएस का उपयोग करने के समान है ।

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

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

मेरा पसंदीदा उपयोग throw new Success()कोड के एक लंबे टुकड़े में एक अनुक्रम है जो एक चीज को एक के बाद एक प्रयास करता है जब तक कि वह यह नहीं पाता कि वह क्या ढूंढ रहा है। प्रत्येक बात - तर्क के प्रत्येक टुकड़े - में घोंसला बनाने वाला घोंसला हो सकता है, इसलिए breakकिसी भी तरह के हालत परीक्षण के रूप में बाहर हैं। if-elseपैटर्न भंगुर है। अगर मैं elseकिसी अन्य तरीके से वाक्य रचना को संपादित करता हूं या गड़बड़ करता हूं , तो एक बालों वाला बग है।

का उपयोग करते हुए throw new Success() linearizes कोड प्रवाह। मैं स्थानीय रूप से परिभाषित Successकक्षाओं का उपयोग करता हूं - निश्चित रूप से जांचा गया - ताकि अगर मैं इसे पकड़ना भूल जाऊं तो कोड संकलित नहीं होगा। और मैं दूसरे तरीके के Successतों को नहीं पकड़ता ।

कभी-कभी मेरा कोड एक के बाद एक चीजों की जांच करता है और केवल तभी सफल होता है जब सब कुछ ठीक हो। इस मामले में मेरे पास एक समान रैखिककरण है throw new Failure()

एक अलग फ़ंक्शन के उपयोग से कम्पार्टमेंटलाइज़ेशन के प्राकृतिक स्तर के साथ खिलवाड़ होता है। तो returnसमाधान इष्टतम नहीं है। मैं संज्ञानात्मक कारणों से एक स्थान पर एक पृष्ठ या दो कोड रखना पसंद करता हूं। मैं अति सूक्ष्म रूप से विभाजित कोड में विश्वास नहीं करता।

जब तक कोई हॉटस्पॉट नहीं होता है तब तक जेवीएम या कंपाइलर मेरे लिए कम प्रासंगिक होते हैं। मुझे विश्वास नहीं हो रहा है कि कंपाइलरों के पास स्थानीय रूप से फेंके गए और पकड़े गए अपवादों का पता नहीं लगाने और gotoमशीन कोड स्तर पर बहुत कुशल एस के रूप में व्यवहार करने का कोई मौलिक कारण है।

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

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

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


3
इस पैटर्न का उपयोग करते हुए, मेरे अधिकांश मोटे कार्यों में अंत में दो छोटे कैच होते हैं - एक सक्सेस के लिए और एक फेल्योर के लिए और यह वह जगह है जहाँ फंक्शन चीजों को लपेटता है जैसे कि सही सर्वलेट रिस्पॉन्स तैयार करना या रिटर्न वैल्यू तैयार करना। रैप-अप करने के लिए एक ही जगह होना अच्छा है। इस returnतरह के प्रत्येक फ़ंक्शन के लिए -pattern विकल्प को दो कार्यों की आवश्यकता होगी। एक बाहरी एक सर्वलेट प्रतिक्रिया या इस तरह के अन्य कार्यों को तैयार करने के लिए, और एक आंतरिक एक गणना करने के लिए। पुनश्च: एक अंग्रेजी के प्रोफेसर शायद सुझाव देंगे कि मैं पिछले पैरा में "आश्चर्यचकित" होने के बजाय "आश्चर्यजनक" का उपयोग करूं
necromancer

11

मानक anwser यह है कि अपवाद नियमित नहीं हैं और उनका उपयोग असाधारण मामलों में किया जाना चाहिए।

एक कारण, जो मेरे लिए महत्वपूर्ण है, वह यह है कि जब मैं try-catchबनाए रखने या डिबग करने वाले सॉफ़्टवेयर में एक नियंत्रण संरचना पढ़ता हूं, तो मैं यह पता लगाने की कोशिश करता हूं कि मूल कोडर ने if-elseसंरचना के बजाय अपवाद हैंडलिंग का उपयोग क्यों किया । और मुझे एक अच्छा जवाब मिलने की उम्मीद है।

याद रखें कि आप न केवल कंप्यूटर के लिए बल्कि अन्य कोडर्स के लिए भी कोड लिखते हैं। एक अपवाद हैंडलर से संबंधित एक शब्दार्थ है जिसे आप केवल इसलिए नहीं फेंक सकते क्योंकि मशीन को कोई आपत्ति नहीं है।


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

9

प्रदर्शन के बारे में कैसे? एक .NET वेब ऐप का परीक्षण करते समय हमने प्रति वेब सर्वर पर 100 नकली उपयोगकर्ताओं को सबसे ऊपर रखा, जब तक कि हमने एक सामान्य-अपवाद अपवाद को निर्धारित नहीं किया और यह संख्या 500 उपयोगकर्ताओं तक बढ़ गई।


8

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

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

उदाहरण के लिए, दूसरी विधि पहले की तुलना में उपयोग करना आसान है:

/**
 * Adds two positive numbers.
 *
 * @param addend1 greater than zero
 * @param addend2 greater than zero
 * @throws AdditionException if addend1 or addend2 is less than or equal to zero
 */
int addPositiveNumbers(int addend1, int addend2) throws AdditionException{
  if( addend1 <= 0 ){
     throw new AdditionException("addend1 is <= 0");
  }
  else if( addend2 <= 0 ){
     throw new AdditionException("addend2 is <= 0");
  }
  return addend1 + addend2;
}

/**
 * Adds two positive numbers.
 *
 * @param addend1 greater than zero
 * @param addend2 greater than zero
 */
public int addPositiveNumbers(int addend1, int addend2) {
  if( addend1 <= 0 ){
     throw new IllegalArgumentException("addend1 is <= 0");
  }
  else if( addend2 <= 0 ){
     throw new IllegalArgumentException("addend2 is <= 0");
  }
  return addend1 + addend2;
}

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

  1. आपको इसे प्रलेखित करने की आवश्यकता नहीं है।
  2. आपको इसके लिए परीक्षण करने की आवश्यकता नहीं है (यह निर्भर करता है कि आपकी इकाई परीक्षण रणनीति कितनी आक्रामक है)।
  3. आपको तीन उपयोग मामलों को संभालने के लिए कॉलर की आवश्यकता नहीं है।

जमीनी स्तर का मुद्दा यह है कि अपवाद का उपयोग रिटर्न कोड के रूप में नहीं किया जाना चाहिए , मोटे तौर पर क्योंकि आपने न केवल अपने एपीआई को जटिल किया है, बल्कि कॉलर के एपीआई को भी।

सही काम करना निश्चित रूप से एक लागत पर आता है। लागत यह है कि सभी को यह समझने की आवश्यकता है कि उन्हें प्रलेखन को पढ़ने और पालन करने की आवश्यकता है। उम्मीद है कि वैसे भी यह मामला है।


7

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

अपवाद बनाने की लागत में कटौती करने का सबसे अच्छा तरीका इस तरह से fillInStackTrace () विधि को ओवरराइड करना है:

public Throwable fillInStackTrace() { return this; }

इस तरह के अपवाद में कोई स्टैकट्रैक नहीं होगा।


स्टैकट्रेस को कॉल करने वाले को "स्टैब पर सभी थ्रोबेबल्स" (यानी एक निर्भरता है) के बारे में जानने की आवश्यकता होती है। यह बुरी बात है। एब्स्ट्रैक्शन के स्तर (सेवा में अपवाद, सेवा में डीएओडिसेप्शन, डाओ विधियों आदि से उपयुक्त) फेंको। यदि आवश्यक हो तो बस अनुवाद करें।
जसोनेरोथिन

5

मैं वास्तव में यह नहीं देखता कि आप अपने कोड में प्रोग्राम फ्लो को कैसे नियंत्रित कर रहे हैं। आपको ArgumentOutOfRange अपवाद के अलावा दूसरा अपवाद कभी नहीं दिखाई देगा। (तो आपका दूसरा कैच क्लॉज कभी हिट नहीं होगा)। यदि आप एक स्टेटमेंट की नकल करते हैं, तो आप बहुत महंगा फेंक का उपयोग कर रहे हैं।

इसके अलावा, आप ऑपरेशन के अधिक भयावह प्रदर्शन नहीं कर रहे हैं, जहाँ आप केवल एक अपवाद को फेंक देते हैं इसके लिए प्रवाह नियंत्रण करने के लिए इसे कहीं और पकड़ा जाता है। आप वास्तव में एक असाधारण मामले को संभाल रहे हैं।


5

यहां मेरे ब्लॉग पोस्ट में वर्णित सर्वोत्तम अभ्यास हैं :

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

4

क्योंकि कोड को पढ़ना मुश्किल है, इसलिए आपको इसे डीबग करने में परेशानी हो सकती है, आप लंबे समय के बाद बग्स को ठीक करते समय नए बग पेश करेंगे, यह संसाधनों और समय के मामले में अधिक महंगा है, और यह आपको परेशान करता है कि क्या आप अपना कोड डीबग कर रहे हैं और डीबगर हर अपवाद की घटना पर रुकता है;)


4

बताए गए कारणों के अलावा, प्रवाह नियंत्रण के लिए अपवादों का उपयोग नहीं करने का एक कारण यह है कि यह डिबगिंग प्रक्रिया को बहुत जटिल कर सकता है।

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


1
मैं पहले से ही उस एक बाघ को संभालता हूं: सभी अपवादों पर डिबगिंग: एक ही, यह सिर्फ इसलिए किया जाता है क्योंकि अपवादों का उपयोग नहीं करने के लिए डिजाइन आम है। मेरा सवाल था: यह पहली जगह में क्यों आम है?
पीटर

तो क्या आपका जवाब मूल रूप से "यह बुरा है क्योंकि विजुअल स्टूडियो में यह एक विशेषता है ..."? मैं अब लगभग 20 वर्षों से प्रोग्रामिंग कर रहा हूं, और मैंने यह भी नहीं देखा कि "सभी अपवादों पर ब्रेक" विकल्प था। फिर भी, "इस एक विशेषता के कारण!" एक कमजोर कारण की तरह लगता है। केवल इसके स्रोत के अपवाद का पता लगाएं; उम्मीद है कि आप एक ऐसी भाषा का उपयोग कर रहे हैं जो इसे आसान बनाती है - अन्यथा आपकी समस्या भाषा की विशेषताओं के साथ है, न कि स्वयं अपवादों के सामान्य उपयोग के साथ।
Loduwijk

3

मान लें कि आपके पास एक तरीका है जो कुछ गणना करता है। कई इनपुट पैरामीटर हैं जिन्हें इसे मान्य करना है, फिर एक संख्या को अधिक से अधिक वापस करना है।

सत्यापन त्रुटि को इंगित करने के लिए वापसी मानों का उपयोग करना, यह सरल है: यदि विधि एक संख्या कम लौटाती है तो 0, एक त्रुटि हुई। फिर कैसे बताएं कि कौन सा पैरामीटर मान्य नहीं हुआ?

मुझे याद है कि मेरे C दिनों से बहुत से फ़ंक्शंस इस तरह से त्रुटि कोड लौटाते हैं:

-1 - x lesser then MinX
-2 - x greater then MaxX
-3 - y lesser then MinY

आदि।

क्या यह वास्तव में कम पठनीय है और एक अपवाद को फेंकना और पकड़ना है?


कि के कारण है कि वे enums का आविष्कार किया :) लेकिन जादुई संख्या एक पूरी तरह से अलग विषय .. है en.wikipedia.org/wiki/...
इसाक Savo

महान उदाहरण है। मैं एक ही बात लिखने वाला था। @IsakSavo: यदि इस पद्धति से कुछ अर्थ मान या वस्तु वापस करने की अपेक्षा की जाती है, तो एनम इस स्थिति में सहायक नहीं हैं। जैसे getAccountBalance () को एक Money ऑब्जेक्ट लौटना चाहिए, एक AccountBalanceResultEnum ऑब्जेक्ट नहीं। बहुत सारे सी कार्यक्रमों में एक समान पैटर्न होता है जहां एक प्रहरी मूल्य (0 या शून्य) एक त्रुटि का प्रतिनिधित्व करता है, और फिर आपको एक अन्य फ़ंक्शन को कॉल करने के लिए एक अलग त्रुटि कोड प्राप्त करना होगा ताकि यह निर्धारित किया जा सके कि त्रुटि क्यों हुई। (MySQL C API इस तरह है।)
मार्क ई। हासे

3

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

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

एक और तरीका है ने कहा: सिर्फ इसलिए कि आप कर सकते हैं इसका मतलब यह नहीं कि आप ऐसा करना चाहिए


1
क्या आप यह कह रहे हैं कि ifसामान्य उपयोग या निष्पादन के उपयोग के लिए मिलने के बाद अपवाद की कोई आवश्यकता नहीं है, क्योंकि यह इरादा नहीं है (परिपत्र तर्क) नहीं है?
वैल

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

उस तर्क से, आपके पास अपवाद नहीं हो सकते हैं और अपवाद को फेंकने के बजाय हमेशा सिस्टम से बाहर निकलें। यदि आप बाहर निकलने से पहले कुछ भी करना चाहते हैं, तो एक आवरण बनाएं और कॉल करें। जावा उदाहरण: public class ExitHelper{ public static void cleanExit() { cleanup(); System.exit(1); } }तो बस यह कहें कि फेंकने के बजाय: ExitHelper.cleanExit();यदि आपका तर्क ध्वनि था, तो यह पसंदीदा तरीका होगा और कोई अपवाद नहीं होगा। आप मूल रूप से कह रहे हैं "अपवादों का एकमात्र कारण एक अलग तरीके से दुर्घटनाग्रस्त होना है।"
लोदुविज्क

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

@BryanWatts ने स्वीकार किया। कई अन्य लोगों ने कहा है कि आपको केवल उन चीजों के लिए अपवादों का उपयोग करना चाहिए जिनसे आप उबर नहीं सकते हैं, और विस्तार से हमेशा अपवादों पर दुर्घटनाग्रस्त होना चाहिए। यही कारण है कि इन चीजों पर चर्चा करना मुश्किल है; वहाँ केवल 2 राय नहीं है, लेकिन कई हैं। मैं अब भी आपसे असहमत हूं, लेकिन दृढ़ता से नहीं। ऐसे समय होते हैं जब फेंक / पकड़ एक साथ सबसे पठनीय, बनाए रखने योग्य, सबसे अच्छे दिखने वाले कोड होते हैं; आमतौर पर यह तब होता है यदि आप पहले से ही अन्य अपवादों को पकड़ रहे हैं, तो आपके पास पहले से ही कोशिश / कैच है और 1 या 2 अधिक कैच जोड़ने से अलग-अलग त्रुटि जांचों की तुलना में क्लीनर है if
लोडुविज्क

3

जैसा कि दूसरों ने कई उल्लेख किया है, कम से कम विस्मय का सिद्धांत यह मना करेगा कि आप केवल नियंत्रण प्रवाह के लिए अपवादों का अत्यधिक उपयोग करते हैं। दूसरी ओर, कोई नियम 100% सही नहीं है, और हमेशा ऐसे मामले होते हैं जहां एक अपवाद "बस सही उपकरण" है - बहुत कुछ gotoअपने आप से, जिस तरह से, जावा के रूप में breakऔर continueभाषाओं में जहाज , जो अक्सर भारी नेस्टेड छोरों से बाहर निकलने का सही तरीका है, जो हमेशा बचने योग्य नहीं होते हैं।

निम्नलिखित ब्लॉग पोस्ट एक गैर-स्थानीय के लिए एक बल्कि जटिल बल्कि बल्कि दिलचस्प उपयोग-मामले की व्याख्या करता है ControlFlowException:

यह बताता है कि कैसे jOOQ (जावा के लिए एक SQL अमूर्त पुस्तकालय) के अंदर , ऐसे अपवाद कभी-कभी SQL रेंडरिंग प्रक्रिया को जल्दी समाप्त करने के लिए उपयोग किए जाते हैं जब कुछ "दुर्लभ" स्थिति मिलती है।

ऐसी स्थितियों के उदाहरण हैं:

  • बहुत सारे बंधे मूल्यों का सामना करना पड़ता है। कुछ डेटाबेस अपने SQL स्टेटमेंट्स (SQLite: 999, Ingres 10.1.0: 1024, Sybase ASE 15.5: 2000, SQL Server 2008: 2100) में बाइंड मानों की मनमानी संख्या का समर्थन नहीं करते हैं। उन मामलों में, jOOQ SQL रेंडरिंग चरण को निरस्त करता है और इनबिल्ड बाइंड मानों के साथ SQL स्टेटमेंट को फिर से प्रस्तुत करता है। उदाहरण:

    // Pseudo-code attaching a "handler" that will
    // abort query rendering once the maximum number
    // of bind values was exceeded:
    context.attachBindValueCounter();
    String sql;
    try {
    
      // In most cases, this will succeed:
      sql = query.render();
    }
    catch (ReRenderWithInlinedVariables e) {
      sql = query.renderWithInlinedBindValues();
    }

    यदि हमने स्पष्ट रूप से हर बार उन्हें गिनने के लिए क्वेरी एएसटी से बाइंड मानों को स्पष्ट रूप से निकाला है, तो हम उन 99.9% प्रश्नों के लिए मूल्यवान सीपीयू चक्र बर्बाद कर देंगे जो इस समस्या से ग्रस्त नहीं हैं।

  • कुछ तर्क केवल एक एपीआई के माध्यम से अप्रत्यक्ष रूप से उपलब्ध हैं जिन्हें हम केवल "आंशिक रूप से" निष्पादित करना चाहते हैं। UpdatableRecord.store()विधि एक उत्पन्न करता है INSERTया UPDATEबयान के आधार पर Recordकी आंतरिक झंडे। "बाहर" से, हम नहीं जानते कि किस प्रकार का तर्क निहित है store()(जैसे आशावादी लॉकिंग, ईवेंट श्रोता हैंडलिंग, आदि) इसलिए हम उस तर्क को दोहराना नहीं चाहते हैं जब हम एक बैच स्टेटमेंट में कई रिकॉर्ड संग्रहीत करते हैं, जहां हम store()केवल SQL स्टेटमेंट जेनरेट करना चाहते हैं , वास्तव में इसे निष्पादित नहीं करते हैं। उदाहरण:

    // Pseudo-code attaching a "handler" that will
    // prevent query execution and throw exceptions
    // instead:
    context.attachQueryCollector();
    
    // Collect the SQL for every store operation
    for (int i = 0; i < records.length; i++) {
      try {
        records[i].store();
      }
    
      // The attached handler will result in this
      // exception being thrown rather than actually
      // storing records to the database
      catch (QueryCollectorException e) {
    
        // The exception is thrown after the rendered
        // SQL statement is available
        queries.add(e.query());                
      }
    }

    अगर हमने store()तर्क को "पुनः प्रयोग करने योग्य" एपीआई में बदल दिया है जो कि एसक्यूएल को निष्पादित नहीं करने के लिए वैकल्पिक रूप से अनुकूलित किया जा सकता है , तो हम इसे बनाए रखने के लिए मुश्किल नहीं बल्कि मुश्किल से पुनः उपयोग करने योग्य एपीआई बनाने में देख रहे होंगे।

निष्कर्ष

संक्षेप में, इन गैर-स्थानीय gotoएस का हमारा उपयोग सिर्फ [मेसन व्हीलर] [5] की पंक्तियों के साथ है:

"मुझे अभी इस स्थिति का सामना करना पड़ा है कि मैं इस बिंदु पर ठीक से व्यवहार नहीं कर सकता, क्योंकि मेरे पास इसे संभालने के लिए पर्याप्त संदर्भ नहीं है, लेकिन दिनचर्या ने मुझे बुलाया (या कॉल स्टैक को कुछ और) यह जानने के लिए कि इसे कैसे संभालना चाहिए। । "

दोनों ControlFlowExceptionsविकल्पों को उनके विकल्पों की तुलना में लागू करना आसान था, जिससे हमें प्रासंगिक आंतरिक से बाहर निकालने के बिना तर्क की एक विस्तृत श्रृंखला का पुन: उपयोग करने की अनुमति मिली।

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


2

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

सामान्य तौर पर यदि आप जानते हैं कि विफलता की एक उच्च संभावना है जिसे आप जांच सकते हैं ... आपको चेक करना चाहिए ... यानी यदि (obj! = Null) obj.method ()!

आपके मामले में, मुझे यह जानने के लिए C # लाइब्रेरी से पर्याप्त परिचित नहीं है कि क्या समय की जाँच करने का एक आसान तरीका है कि टाइमस्टैम्प सीमा से बाहर है या नहीं। यदि ऐसा होता है, तो बस (.isvalid (ts)) कॉल करें अन्यथा आपका कोड मूल रूप से ठीक है।

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


Add'l बिंदु: यदि आपका अपवाद विफलता कैप्चर जानकारी ("परम getWhatParamMessedMeUp ()" जैसे एक गेट्टर) प्रदान करता है, तो यह आपके एपीआई के उपयोगकर्ता को आगे क्या करने के बारे में एक अच्छा निर्णय लेने में मदद कर सकता है। अन्यथा, आप केवल एक त्रुटि स्थिति को नाम दे रहे हैं।
जसोनेरोथिन

2

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

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

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

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

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

अंत में, सामने की गई सभी जाँचों से पता चलता है कि आप क्या जानते हैं या उम्मीद करते हैं और यह स्पष्ट हो जाएगा। आशय में कोड स्पष्ट होना चाहिए। आप क्या पढ़ेंगे?


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

2

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

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

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


2

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

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

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


2

एक सौंदर्य कारण:

एक कोशिश हमेशा एक पकड़ के साथ आती है, जबकि अगर एक को दूसरे के साथ नहीं आना पड़ता है।

if (PerformCheckSucceeded())
   DoSomething();

कोशिश / पकड़ के साथ, यह बहुत अधिक क्रिया हो जाता है।

try
{
   PerformCheckSucceeded();
   DoSomething();
}
catch
{
}

कोड की 6 पंक्तियाँ बहुत अधिक हैं।


1

लेकिन आपको हमेशा यह नहीं पता होगा कि आपके द्वारा कॉल की जाने वाली विधि / विधियों में क्या होता है। आपको बिल्कुल नहीं पता होगा कि अपवाद कहां फेंका गया था। अधिक विस्तार में अपवाद वस्तु की जांच के बिना ...।


1

मुझे लगता है कि आपके उदाहरण में कुछ भी गलत नहीं है। इसके विपरीत, इसे फंक्शन कहे जाने वाले अपवाद को अनदेखा करना पाप होगा।

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


क्षमा करें, यह सादा गलत है, ब्रान। यह स्थिति पर निर्भर करता है। यह हमेशा ऐसा नहीं होता है कि स्थिति तुच्छ है। इस प्रकार, यदि एक बयान में घंटे या दिन या उससे भी अधिक समय लग सकता है।
इंगो

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

1
इंगो: एक असाधारण स्थिति वह है जिसकी आप उम्मीद नहीं करते हैं। यानी एक आप एक प्रोग्रामर के रूप में नहीं सोचा है। तो मेरा नियम है "कोड लिखें जो अपवादों को नहीं फेंकता है" :)
ब्रॉन

1
मैं अपवाद हैंडलर कभी नहीं लिखता, मैं हमेशा समस्या को ठीक करता हूं (जब मैं ऐसा नहीं कर सकता, क्योंकि मुझे गलती कोड पर नियंत्रण नहीं है)। और मैं अपवादों को कभी नहीं फेंकता, सिवाय इसके जब मैंने जो कोड लिखा है वह किसी और के लिए उपयोग करने के लिए है (जैसे एक पुस्तकालय)। कोई विरोधाभास मुझे नहीं दिखा?
ब्रॉन

1
मैं अपवादों को बेतहाशा न फेंकने के लिए आपसे सहमत हूं। लेकिन निश्चित रूप से, "असाधारण" क्या परिभाषा का सवाल है। यह String.parseDouble एक अपवाद फेंकता है अगर यह एक उपयोगी परिणाम नहीं दे सकता है, उदाहरण के लिए, क्रम में है। और क्या करना चाहिए? NaN लौटाओ? गैर IEEE हार्डवेयर के बारे में क्या?
इंगो

1

कुछ सामान्य तंत्र हैं, जिनके माध्यम से एक भाषा बिना मूल्य वापस लिए बाहर निकलने की विधि की अनुमति दे सकती है और अगले "कैच" ब्लॉक में ले जा सकती है:

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

  • क्या विधि एक "छिपा हुआ" ध्वज लौटाती है जो एक अपवाद से एक सामान्य वापसी को अलग करती है, और कॉलर को उस ध्वज और शाखा को एक "अपवाद" दिनचर्या में जाँचता है यदि यह सेट है। यह दिनचर्या बिना किसी अपवाद के मामले में 1-2 निर्देश जोड़ती है, लेकिन अपवाद होने पर अपेक्षाकृत कम ओवरहेड।

  • स्टैक्ड रिटर्न पते के सापेक्ष एक निश्चित पते पर कॉलर को अपवाद-हैंडलिंग जानकारी या कोड रखें। उदाहरण के लिए, ARM के साथ, निर्देश "BL सबरूटीन" का उपयोग करने के बजाय, कोई अनुक्रम का उपयोग कर सकता है:

        adr lr,next_instr
        b subroutine
        b handle_exception
    next_instr:
    

सामान्य रूप से बाहर निकलने के लिए, सबरूटीन बस bx lrया करेगाpop {pc} ; एक असामान्य निकास के मामले में, सबरूटीन या तो एलआर से 4 घटाएगा वापसी या उपयोग करने से पहले sub lr,#4,pc(एआरएम भिन्नता, निष्पादन मोड, आदि के आधार पर) यह दृष्टिकोण बहुत बुरी तरह से खराबी होगा यदि कॉलर इसे समायोजित करने के लिए डिज़ाइन नहीं किया गया है।

एक भाषा या ढांचा, जो जाँच किए गए अपवादों का उपयोग करता है, को # 2 या # 3 से ऊपर की तरह एक तंत्र के साथ नियंत्रित करने से लाभ हो सकता है, जबकि अनियंत्रित अपवाद # 1 का उपयोग करके नियंत्रित किए जाते हैं। हालांकि जावा में चेक किए गए अपवादों का कार्यान्वयन उपद्रवपूर्ण है, वे एक बुरा अवधारणा नहीं होंगे यदि कोई ऐसा साधन था जिसके द्वारा कॉल साइट कह सकती है, अनिवार्य रूप से, "इस विधि को XX फेंकने के रूप में घोषित किया गया है, लेकिन मुझे इसकी उम्मीद नहीं है ऐसा करने के लिए, यदि ऐसा होता है, तो एक "अनियंत्रित" अपवाद के रूप में फिर से उखाड़ फेंकें। ऐसे ढांचे में जहां जाँच किए गए अपवादों को इस तरह से नियंत्रित किया गया था, वे पार्सिंग विधियों जैसी चीजों के लिए प्रवाह नियंत्रण का एक प्रभावी साधन हो सकते हैं जो कुछ संदर्भों में हो सकते हैं। असफलता की उच्च संभावना, लेकिन जहां असफलता को सफलता की तुलना में मौलिक रूप से अलग जानकारी वापस करनी चाहिए। ' हालांकि इस तरह के पैटर्न का उपयोग करने वाले किसी भी ढांचे से अनजान हैं। इसके बजाय, अधिक सामान्य पैटर्न ऊपर के पहले दृष्टिकोण का उपयोग करना है (सभी अपवादों के लिए न्यूनतम लागत, लेकिन अपवादों को फेंकने पर उच्च लागत)।

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