एक ही फ़ंक्शन / पद्धति में अपवादों को फेंकना और पकड़ना


10

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

मुझे आश्चर्य है कि अन्य डेवलपर्स इस बारे में क्या सोचते हैं। मैं भी फंक्शन में अपवादों का गलत इस्तेमाल कर रहा हूं। यहाँ जावा में कोड है:

private static int sideInput()
{
    int side = 0;
    String input;
    Scanner scanner = new Scanner(System.in);

    do {
        System.out.print("Side length: ");
        input = scanner.nextLine();
        try {
            side = Integer.parseInt(input);
            if (side <= 0) {
                // probably a misuse of exceptions
                throw new NumberFormatException();
            }
        }
        catch (NumberFormatException numFormExc) {
            System.out.println("Invalid input. Enter a natural number.");
        }
    } while (side <= 0);

    return side;
}

मुझे दो चीजों में दिलचस्पी है:

  1. क्या मुझे कॉलर को अपवादों के बारे में चिंता करने देना चाहिए? फ़ंक्शन का मुद्दा यह है कि यह उपयोगकर्ता को तब तक नंगा करता है जब तक कि उपयोगकर्ता एक प्राकृतिक संख्या में प्रवेश नहीं करता है। क्या फ़ंक्शन का बिंदु खराब है? मैं यूआई के बारे में बात नहीं कर रहा हूं (उपयोगकर्ता उचित इनपुट के बिना लूप से बाहर निकलने में सक्षम नहीं है), लेकिन अपवादित हैंडल के साथ लूप किए गए इनपुट के बारे में।
  2. क्या आप कहेंगे कि इस कथन (इस मामले में) अपवादों का दुरुपयोग है? मैं आसानी से संख्या की वैधता की जाँच के लिए एक ध्वज बना सकता था और उस ध्वज के आधार पर चेतावनी संदेश का उत्पादन कर सकता था। लेकिन इससे कोड में अधिक लाइनें जुड़ जाएंगी और मुझे लगता है कि यह पूरी तरह से पठनीय है।

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


अत्यधिक भाषा पर निर्भर करता है। कुछ भाषाएँ दूसरों की तुलना में अपवादों का अधिक स्वतंत्र रूप से उपयोग करती हैं।
मार्टिन यॉर्क

जवाबों:


11

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

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


हाँ, यही कारण है कि मुझे लगा कि यह एक दुरुपयोग था। तो, उस फेंक स्टेटमेंट को नजरअंदाज करते हुए, आप सहमत होते हैं कि कॉल करने वाले को उन्हें पकड़ने देने के बजाय किसी फ़ंक्शन के अंदर ऐसे लूप में अपवादों को संभालना ठीक है? Integer.parseInt (फिर से, अनदेखी को देखते हुए) के कारण कैच का विवरण है।
usr

1
@usr: यह उत्तर इस बात पर अधिक निर्भर करता है कि बाकी सिस्टम एक साथ काम करने के लिए कैसा है। अपवादों को किसी बिंदु पर संभालने की आवश्यकता है। कुछ अलग तरीके हैं जो आप इसे व्यवस्थित कर सकते हैं और यह उनमें से एक है। जो सबसे अच्छी है वह अन्य जानकारी पर निर्भर करता है जो हमारे यहाँ नहीं है।
अनहेल्सीप्लमर

4

यह अपवादों का गलत उपयोग है। शुरू करने के लिए, एक गैर-सकारात्मक संख्या एक प्रारूप अपवाद नहीं है।

अपवादों का उपयोग क्यों करें? यदि आप जानते हैं कि इनपुट की अनुमति नहीं है, तो बस लूप से बाहर न निकलें जब तक कि उपयोगकर्ता से वैध इनपुट न मिले, कुछ इस तरह है:

while (true)
{
   // Get user input.
   String input = scanner.nextLine();

   try
   {
      side = Integer.parseInt(input);

      break;
   }
   catch (NumberFormatException ex)
   {
      // Inform user of invalid input.
      System.out.println("Invalid input. Enter a natural number.");
   }
}

Integer.intParse एक प्रारूप अपवाद को फेंकता है, इसलिए कैच स्टेटमेंट का उपयोग करना पूरी तरह से मान्य है। मैं मुख्य रूप से जानना चाहता हूं कि क्या किसी फ़ंक्शन में लूप में कैच स्टेटमेंट का उपयोग करना ठीक है या मुझे फ़ंक्शन के कॉलर को प्रारूप के अपवाद को संभालने देना चाहिए।
usr

Integer.parseInt()NumberFormatExceptionयदि यह प्रदान किए गए स्ट्रिंग तर्क को पार्स नहीं कर सकता है तो फेंकता है । खुद को अपवाद फेंकने के लिए आपको (और आप सक्षम नहीं होंगे) की कोई आवश्यकता नहीं है।
बर्नार्ड

मैंने कोड उदाहरण को अधिक स्पष्ट होने के लिए संपादित किया है।
बर्नार्ड

"और आप खुद को अपवाद नहीं बना पाएंगे)" - आपका वहां क्या मतलब है?
माइकल बोर्गवर्ड

@ मिचेल बोर्गवर्ड: मेरा मतलब है कि चूंकि Integer.parseInt()विधि आपके लिए अपवाद को फेंक देगी यदि ऐसा होता है, तो आप इसे बाद में फेंक नहीं पाएंगे क्योंकि यह पहले ही फेंक दिया गया है।
बर्नार्ड

1

केवल अपवादों को पकड़ें यदि आप कुछ ऐसा करने का इरादा रखते हैं जो वर्तमान विधि कॉल के लिए प्रासंगिक हो; यानी क्लीनअप, विफलता तर्क आदि। इस मामले में, पकड़ केवल कंसोल को एक संदेश भेज रहा है, यह साइडइन्पुट विधि के लिए प्रासंगिक नहीं है, इसलिए इसे कॉल चेन / स्टैक तक आगे संभाला जा सकता है।

यहां से कोशिश / पकड़ से छुटकारा पा सकते हैं और बस विधि कॉल को दस्तावेज कर सकते हैं:

//Throws NumberFormatException if read input is less than 0
private static int sideInput()

एक को अभी भी उस अपवाद को संभालने की आवश्यकता है जो कॉल श्रृंखला / स्टैक को आगे बढ़ाता है!


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

1

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

यदि parseIntसफल रहा, तो यह नहीं है NumberFormatException

यदि पक्ष शून्य से कम है, तो आपको फेंक देना चाहिए NegativeSideLengthException;

नामित एक कस्टम / bussiness अपवाद बनाएँ NegativeSideLengthException

public class NegativeSideLengthException extends Exception
{


    public NegativeSideLengthException(Integer i)
    {
        super("Invalid negative side length "+i);        
    }

}

इसके बाद sideInputनेगेटिवसाइडलिफ्ट एक्ससेप्शन फेंकता है

private static int sideInput() throws NegativeSideLengthException
{
    int side = 0;
    String input;
    Scanner scanner = new Scanner(System.in);

    do {
        System.out.print("Side length: ");
        input = scanner.nextLine();
        try {
            side = Integer.parseInt(input);
            if (side <= 0) {
                throw new NegativeSideLengthException(side);
            }
        }
        catch (NumberFormatException numFormExc) {
            System.out.println("Invalid input. Enter a natural number.");
        }
    } while (side <= 0);

    return side;
}

आप (यदि आप चाहें तो) पकड़ने के लिए एक और पकड़ ब्लॉक जोड़ सकते हैं और NegativeSideLengthExceptionइसे फेंकने की विधि नहीं है।

do {
    System.out.print("Side length: ");
    input = scanner.nextLine();
    try {
        side = Integer.parseInt(input);
        if (side <= 0) {
            throw new NegativeSideLengthException(side);
        }
    }
    catch (NumberFormatException numFormExc) {
        System.out.println("Invalid input. Enter a natural number.");
    } catch (NegativeSideLengthException e){
        System.out.println("Invalid input. Enter a non-negative number.");
    }
} while (side <= 0);

अपवादों को संभालने के लिए झंडे एक अच्छा तरीका नहीं हैं।


-1

अपवाद बहुत बुरे सपने हैं, वे हल करने की तुलना में अधिक जटिलताएं लाते हैं।

सबसे पहले, यदि आप अपने अपवादों को नहीं पकड़ते हैं, तो कॉलर केवल on error resume nextएक सप्ताह के बाद ही कर सकता है, यहां तक ​​कि आपको यह भी नहीं पता होगा कि आपका फ़ंक्शन क्या फेंक सकता है, और इसके साथ क्या करना है:

{
    ...
}
catch(OutOfMemory, CorruptedMemory, BadData, DanglingPointers, UnfinishedCommit)
{
    Console.WriteLine("Nothing to see here, move on.");
    Console.WriteLine("The app is very stable, see, no crashing!");
}

मूल रूप से, यदि आप उन्हें पकड़ते हैं, तो आपको अनुबंधों और अपवाद की गारंटी के बारे में बहुत अच्छी समझ होनी चाहिए। ऐसा शायद ही कभी किसी वास्तविक दुनिया में होता है। और आपका कोड भी पढ़ना मुश्किल होगा।

इसके अलावा, मजेदार बात यह है कि यदि आपके पास वास्तव में अपवादों को संभालने का कोई मौका है, तो आपको वास्तविक RAII भाषा की आवश्यकता है, जो कि विनोदी है, चूंकि Java और .NET अपवादों के बारे में है ...

इसे एक बार फिर दोहराते हुए, लेकिन ...:

http://blogs.msdn.com/b/oldnewthing/archive/2004/04/22/118161.aspx

http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx

http://www.joelonsoftware.com/items/2003/10/13.html


4
-1, बॉर्डरलाइन शेख़ी पोस्ट करने के लिए, ओपी के वास्तविक सवाल का जवाब देने के बजाय , कम से कम संदर्भ / भाषा पर निर्भर बयानों से भरा नहीं ।
Péter Török

@ PéterTörök: "एक आदमी को एक मछली दें और आप उसे एक दिन के लिए खिलाएं। एक आदमी को मछली सिखाएं और आप उसे जीवन भर के लिए खिलाएं।" अपवादों के पीछे बहुत गंभीर समस्याएं हैं, और लोगों को उन्हें -1000 / + 1 जानना चाहिए, मुझे वास्तव में परवाह नहीं है।
कोडर

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

@ PéterTörök: यह एक राय नहीं है, यह एक तथ्य है, हर बार जब आप एक घटक का उपयोग करते हैं जो आंतरिक रूप से एक अपवाद को फेंकता है, तो आपको पूरे पदानुक्रम को क्रॉल करना होगा और कोड की हर एक पंक्ति की जांच करनी होगी ताकि यह पता चल सके कि क्या पकड़ना है, और यदि घटक मजबूत प्रदान करते हैं। गारंटी, और सब कुछ वापस लुढ़का हुआ है, या यदि वह पकड़ सुरक्षा की झूठी भावना है। बिल्ली, आप सभी अपवादों को भी नहीं जानते हैं :: स्ट्रिंग फेंकता है, आप चश्मा देख सकते हैं, लेकिन आप कभी नहीं पाएंगे। जैसी चीजें : throw(thisexception, thatexception)सर्वथा गलत हैं और कभी भी इसका उपयोग नहीं किया जाना चाहिए, क्योंकि अन्यथा आपको अप्रत्याशितता मिलेगी।
कोडर

2
ठीक है, तो कोड का अपवादों का उपयोग नहीं करने के बारे में कैसे? जी, आपको यह देखने के लिए कोड के माध्यम से क्रॉल करने की आवश्यकता है कि क्या रिटर्न मान को ठीक से अनदेखा किया गया है या नहीं। और जब एक रिटर्न वैल्यू को नजरअंदाज किया जाता है, तब तक कोई नोटिस नहीं देता है जब तक कि आपका ऐप बाद में कुछ हज़ार लाइनों को क्रैश न कर दे। कम से कम अपवाद आपको नोटिस करने के लिए मजबूर करते हैं। हां, आप उन्हें निगल सकते हैं - लेकिन केवल एक स्पष्ट के साथ catch। जबकि एक अनदेखा वापसी मूल्य अनुपलब्ध है - यह केवल लाइन-बाय-लाइन कोड समीक्षा के माध्यम से पहचाने जाने योग्य है। अंतिम लेकिन कम से कम, निर्माणकर्ताओं के पास कोई वापसी मूल्य नहीं है, यह अपवादों का उपयोग करने का सबसे महत्वपूर्ण कारण है।
पेटर तोर्क
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.