कोशिश करनी चाहिए ... लूप के अंदर या बाहर जाना चाहिए?


184

मेरे पास एक लूप है जो कुछ इस तरह दिखता है:

for (int i = 0; i < max; i++) {
    String myString = ...;
    float myNum = Float.parseFloat(myString);
    myFloats[i] = myNum;
}

यह एक विधि की मुख्य सामग्री है जिसका एकमात्र उद्देश्य फ्लोट्स के सरणी को वापस करना है। मैं चाहता हूं कि nullअगर कोई त्रुटि हो तो मैं वापस आ जाऊं, इसलिए मैंने लूप को एक try...catchब्लॉक के अंदर रखा , जैसे:

try {
    for (int i = 0; i < max; i++) {
        String myString = ...;
        float myNum = Float.parseFloat(myString);
        myFloats[i] = myNum;
    }
} catch (NumberFormatException ex) {
    return null;
}

लेकिन फिर मैंने try...catchइस तरह से ब्लॉक को लूप के अंदर डालने का सोचा , जैसे:

for (int i = 0; i < max; i++) {
    String myString = ...;
    try {
        float myNum = Float.parseFloat(myString);
    } catch (NumberFormatException ex) {
        return null;
    }
    myFloats[i] = myNum;
}

क्या कोई कारण, प्रदर्शन या अन्यथा, एक से दूसरे को पसंद करना है?


संपादित करें: सर्वसम्मति से ऐसा लगता है कि लूप को ट्राई / कैच के अंदर रखने के लिए क्लीनर है, संभवतः अपने तरीके से। हालांकि, इस पर अभी भी बहस जारी है कि कौन सी बात तेज है। क्या कोई इसका परीक्षण कर सकता है और एकीकृत उत्तर के साथ वापस आ सकता है?


2
मुझे प्रदर्शन के बारे में पता नहीं है, लेकिन कोड लूप के लिए बाहर की कोशिश के साथ क्लीनर दिखता है।
जैक बी निंबले

जवाबों:


132

प्रदर्शन:

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

यहाँ एक संदर्भ है: http://www.javaworld.com/javaworld/jw-01-1997/jw-01-hood.html

तालिका का वर्णन लगभग आधे-अधूरे तरीके से किया गया है।


ठीक है, इसलिए आप कह रहे हैं कि सौंदर्यशास्त्र को छोड़कर कोई अंतर नहीं है। क्या आप किसी स्रोत से लिंक कर सकते हैं?
माइकल मायर्स

2
धन्यवाद। मुझे लगता है कि 1997 के बाद से चीजें बदल सकती हैं, लेकिन वे शायद ही इसे कम कुशल बनाते हैं ।
माइकल मायर्स

1
बिलकुल एक कठिन शब्द है। कुछ मामलों में यह कंपाइलर ऑप्टिमाइजेशन को बाधित कर सकता है। प्रत्यक्ष लागत नहीं है, लेकिन यह एक अप्रत्यक्ष प्रदर्शन जुर्माना हो सकता है।
टॉम हॉल्टिन -

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

1
कोई प्रदर्शन अंतर नहीं है, केवल अगर कोड अपवाद के बिना चलता है।
ओनूर बैय्यक

72

प्रदर्शन : जैसा कि जेफरी ने अपने जवाब में कहा, जावा में इससे बहुत फर्क नहीं पड़ता।

आमतौर पर , कोड की पठनीयता के लिए, अपवाद को पकड़ने के लिए आपकी पसंद जहां पर निर्भर करती है कि आप लूप को प्रसंस्करण रखना चाहते हैं या नहीं।

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

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

class Parsing
{
    public static Float MyParseFloat(string inputValue)
    {
        try
        {
            return Float.parseFloat(inputValue);
        }
        catch ( NumberFormatException e )
        {
            return null;
        }
    }

    // ....  your code
    for(int i = 0; i < max; i++) 
    {
        String myString = ...;
        Float myNum = Parsing.MyParseFloat(myString);
        if ( myNum == null ) return;
        myFloats[i] = (float) myNum;
    }
}

1
ध्यान से देखो। वह दोनों में पहले अपवाद पर बाहर निकल रहा है। मैंने भी यही बात पहले सोची थी।
kervin

2
मुझे पता था, इसीलिए मैंने उसके मामले में कहा था, क्योंकि वह लौट रहा है जब वह किसी समस्या से टकराता है तो मैं एक बाहरी कैद का उपयोग करूँगा। स्पष्टता के लिए, यही वह नियम है जिसका मैं उपयोग करूंगा ...
Ray Hayes

अच्छा कोड है, लेकिन दुर्भाग्य से जावा के पास आउट मापदंडों का विलास नहीं है।
माइकल मायर्स

ByRef? जब से मैंने जावा को छुआ है, तब तक ऐसा रहा है!
रे हायस

2
किसी और ने TryParse को सुझाव दिया है जो C # / में है। नेट आपको अपवादों से निपटने के बिना एक सुरक्षित पार्स करने की अनुमति देता है, जिसे अब दोहराया गया है और विधि पुन: प्रयोज्य है। मूल प्रश्न के रूप में, मैं कैच के अंदर लूप को प्राथमिकता दूंगा, यह केवल प्रदर्शन के मुद्दे पर न होने पर भी साफ दिखता है ..
Ray Hayes

46

ऑल राइट, जेफरी एल व्हिटलेज ने कहा कि प्रदर्शन में कोई अंतर नहीं था (1997 तक), मैंने जाकर इसका परीक्षण किया। मैंने इस छोटे बेंचमार्क को चलाया:

public class Main {

    private static final int NUM_TESTS = 100;
    private static int ITERATIONS = 1000000;
    // time counters
    private static long inTime = 0L;
    private static long aroundTime = 0L;

    public static void main(String[] args) {
        for (int i = 0; i < NUM_TESTS; i++) {
            test();
            ITERATIONS += 1; // so the tests don't always return the same number
        }
        System.out.println("Inside loop: " + (inTime/1000000.0) + " ms.");
        System.out.println("Around loop: " + (aroundTime/1000000.0) + " ms.");
    }
    public static void test() {
        aroundTime += testAround();
        inTime += testIn();
    }
    public static long testIn() {
        long start = System.nanoTime();
        Integer i = tryInLoop();
        long ret = System.nanoTime() - start;
        System.out.println(i); // don't optimize it away
        return ret;
    }
    public static long testAround() {
        long start = System.nanoTime();
        Integer i = tryAroundLoop();
        long ret = System.nanoTime() - start;
        System.out.println(i); // don't optimize it away
        return ret;
    }
    public static Integer tryInLoop() {
        int count = 0;
        for (int i = 0; i < ITERATIONS; i++) {
            try {
                count = Integer.parseInt(Integer.toString(count)) + 1;
            } catch (NumberFormatException ex) {
                return null;
            }
        }
        return count;
    }
    public static Integer tryAroundLoop() {
        int count = 0;
        try {
            for (int i = 0; i < ITERATIONS; i++) {
                count = Integer.parseInt(Integer.toString(count)) + 1;
            }
            return count;
        } catch (NumberFormatException ex) {
            return null;
        }
    }
}

मैंने javap का उपयोग करके परिणामी बायटेकोड की जाँच की ताकि यह सुनिश्चित हो सके कि कुछ भी इनलेट न हो।

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

इसलिए, केवल विचार वही है जो सबसे साफ दिखता है। मुझे लगता है कि दूसरा रास्ता बदसूरत है, इसलिए मैं या तो पहले रास्ते पर रहूंगा या रे हेयस के रास्ते से


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

16

हालांकि प्रदर्शन समान हो सकता है और "बेहतर" दिखना बहुत ही व्यक्तिपरक है, कार्यक्षमता में अभी भी बहुत बड़ा अंतर है। निम्नलिखित उदाहरण लें:

Integer j = 0;
    try {
        while (true) {
            ++j;

            if (j == 20) { throw new Exception(); }
            if (j%4 == 0) { System.out.println(j); }
            if (j == 40) { break; }
        }
    } catch (Exception e) {
        System.out.println("in catch block");
    }

जबकि लूप ट्राई कैच ब्लॉक के अंदर होता है, चर 'j' को 40 हिट होने तक इंक्रीमेंट किया जाता है, प्रिंट किया जाता है जब j mod 4 शून्य होता है और j हिट 20 होने पर एक अपवाद को फेंक दिया जाता है।

किसी भी विवरण से पहले, यहां अन्य उदाहरण:

Integer i = 0;
    while (true) {
        try {
            ++i;

            if (i == 20) { throw new Exception(); }
            if (i%4 == 0) { System.out.println(i); }
            if (i == 40) { break; }

        } catch (Exception e) { System.out.println("in catch block"); }
    }

ऊपर के समान तर्क, केवल अंतर यह है कि कोशिश / कैच ब्लॉक अब लूप के अंदर है।

यहाँ आउटपुट आता है (जबकि कोशिश / पकड़ में):

4
8
12 
16
in catch block

और अन्य आउटपुट (कोशिश / समय में पकड़):

4
8
12
16
in catch block
24
28
32
36
40

वहाँ आप काफी महत्वपूर्ण अंतर है:

लूप से बाहर निकलने की कोशिश में / पकड़ते समय

लूप को सक्रिय रखते हुए कोशिश / पकड़


इसलिए try{} catch() {}लूप के चारों ओर रखो अगर लूप को एक "इकाई" के रूप में माना जाता है और उस इकाई में एक समस्या खोजने से पूरी "इकाई" (या इस मामले में लूप) दक्षिण में चली जाती है। try{} catch() {}लूप के अंदर रखें यदि आप लूप के एकल पुनरावृत्ति का इलाज कर रहे हैं, या एक सरणी में एक एकल तत्व पूरे "यूनिट" के रूप में। यदि उस "इकाई" में कोई अपवाद होता है, तो हम उस तत्व को छोड़ देते हैं और फिर हम लूप के अगले पुनरावृत्ति पर जारी रखते हैं।
गैलेक्सी

14

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

इस थोड़ा संशोधित उदाहरण पर विचार करें:

public static void main(String[] args) {
    String[] myNumberStrings = new String[] {"1.2345", "asdf", "2.3456"};
    ArrayList asNumbers = parseAll(myNumberStrings);
}

public static ArrayList parseAll(String[] numberStrings){
    ArrayList myFloats = new ArrayList();

    for(int i = 0; i < numberStrings.length; i++){
        myFloats.add(new Float(numberStrings[i]));
    }
    return myFloats;
}

यदि आप चाहते हैं कि किसी भी त्रुटि (मूल उदाहरण की तरह) को वापस करने के लिए parseAll () विधि हो, तो आप इस तरह से बाहर की कोशिश / पकड़ डालेंगे:

public static ArrayList parseAll1(String[] numberStrings){
    ArrayList myFloats = new ArrayList();
    try{
        for(int i = 0; i < numberStrings.length; i++){
            myFloats.add(new Float(numberStrings[i]));
        }
    } catch (NumberFormatException nfe){
        //fail on any error
        return null;
    }
    return myFloats;
}

वास्तव में, आपको संभवतः अशक्त के बजाय यहां एक त्रुटि वापस करनी चाहिए, और आमतौर पर मुझे कई रिटर्न प्राप्त करना पसंद नहीं है, लेकिन आपको यह विचार मिलता है।

दूसरी ओर, यदि आप चाहते हैं कि यह सिर्फ समस्याओं को नजरअंदाज करे, और जो कुछ भी हो सकता है, उसे पार्स करें, तो आप इस तरह से लूप के अंदर की कोशिश को पकड़ लेंगे:

public static ArrayList parseAll2(String[] numberStrings){
    ArrayList myFloats = new ArrayList();

    for(int i = 0; i < numberStrings.length; i++){
        try{
            myFloats.add(new Float(numberStrings[i]));
        } catch (NumberFormatException nfe){
            //don't add just this one
        }
    }

    return myFloats;
}

2
इसलिए मैंने कहा "यदि आप केवल एक बुरा मूल्य पकड़ना चाहते हैं, लेकिन प्रसंस्करण जारी रखते हैं, तो इसे अंदर रखें।"
रे हायस

5

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


यह इस विशेष मामले के लिए सच नहीं है (मैं कैच ब्लॉक में लौट रहा हूं), लेकिन सामान्य रूप से ध्यान में रखना अच्छी बात है।
माइकल मायर्स

4

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


4

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

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


2

आपके उदाहरणों में कोई कार्यात्मक अंतर नहीं है। मुझे आपका पहला उदाहरण अधिक पठनीय लगता है।


2

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

एक और नोट पर, आपको शायद फ़्लोट में देखना चाहिए। ट्रायपर्स या Convert.ToFloat।


2

यदि आप लूप के अंदर ट्राई / कैच डालते हैं, तो आप अपवाद के बाद लूपिंग रखेंगे। यदि आप इसे लूप के बाहर रख देते हैं तो अपवाद के रूप में फेंकते ही आप रुक जाएंगे।


ठीक है, मैं अपवाद पर अशक्त लौट रहा हूं, इसलिए यह मेरे मामले में प्रसंस्करण नहीं रखेगा।
माइकल मायर्स

2

मेरा नजरिया यह होगा कि उचित अपवाद से निपटने के लिए ब्लॉक को पकड़ना / पकड़ना आवश्यक है, लेकिन इस तरह के ब्लॉक बनाने से प्रदर्शन प्रभाव पड़ता है। चूँकि, लूप्स में गहन दोहराव वाले संगणनाएँ होती हैं, इसलिए कोशिश की जाती है कि लूप के अंदर ट्राई / कैच ब्लॉक न लगाए जाएँ। इसके अतिरिक्त, ऐसा लगता है कि जहां यह स्थिति होती है, यह अक्सर "अपवाद" या "रनटाइम एक्ससेप्शन" होता है जो पकड़ा जाता है। कोड में पकड़े जा रहे RuntimeException से बचा जाना चाहिए। फिर, यदि आप किसी बड़ी कंपनी में काम करते हैं, तो उस अपवाद को ठीक से लॉग इन करना आवश्यक है, या रनटाइम अपवाद को रोकने के लिए। इस विवरण का पूरा बिंदु हैPLEASE AVOID USING TRY-CATCH BLOCKS IN LOOPS


1

कोशिश / पकड़ के लिए एक विशेष स्टैक फ्रेम स्थापित करने से अतिरिक्त ओवरहेड जुड़ जाता है, लेकिन जेवीएम इस तथ्य का पता लगाने में सक्षम हो सकता है कि आप वापस आ रहे हैं और इसे दूर अनुकूलित करें।

पुनरावृत्तियों की संख्या के आधार पर, प्रदर्शन अंतर नगण्य होगा।

हालाँकि मैं अन्य लोगों से सहमत हूँ कि यह लूप के बाहर होने से लूप बॉडी साफ दिखती है।

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


1

अगर यह अंदर है, तो आप एन / बार संरचना को पकड़ने की कोशिश करेंगे, जैसा कि बाहर की तरफ एक बार किया गया है।


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


क्या आप ओवरहेड पर थोड़ा विस्तार कर सकते हैं?
माइकल मायर्स

1
ठीक है, लेकिन जेफरी एल व्हाइटलेज कहते हैं कि कोई अतिरिक्त उपरि नहीं है। क्या आप कोई स्रोत प्रदान कर सकते हैं जो कहता है कि वहाँ है?
माइकल मायर्स

लागत छोटी है, लगभग नगण्य है, लेकिन यह वहां है - सब कुछ की लागत है। यहाँ .NET से संबंधित प्रोग्रामर हैवेन ( small.cc/ZBX1b ) का ब्लॉग लेख दिया गया है और यहाँ Reshat Sabiq से JAVA ( small.cc/BV2hS ) के बारे में एक समाचार समूह पोस्ट है
स्टीफन राइट

मैं देख रहा हूं ... तो अब सवाल यह है कि क्या ट्रायल / कैच (जिस स्थिति में यह लूप के बाहर होना चाहिए) में प्रवेश करने पर होने वाली लागत है, या यह ट्राइ / कैच की अवधि के लिए स्थिर है (किस स्थिति में लूप के अंदर होना चाहिए)? आप कहते हैं कि यह # 1 है। और मैं अभी भी पूरी तरह से आश्वस्त नहीं हूं कि एक लागत है।
माइकल मायर्स

1
इस Google पुस्तक ( smallurl.com/3pp7qj ) के अनुसार, "नवीनतम VMs कोई दंड नहीं दिखाते हैं"।
माइकल मायर्स

1

अपवादों का पूरा बिंदु पहली शैली को प्रोत्साहित करना है: त्रुटि से निपटने को समेकित करना और एक बार संभाला जाना, हर संभव त्रुटि साइट पर तुरंत नहीं।


गलत! अपवादों का बिंदु यह निर्धारित करना है कि "त्रुटि" होने पर किस असाधारण व्यवहार को अपनाना है। इस प्रकार आंतरिक या बाहरी कोशिश / कैच ब्लॉक चुनना वास्तव में इस बात पर निर्भर करता है कि आप लूप उपचार को कैसे संभालना चाहते हैं।
gizmo

पूर्व-अपवाद त्रुटि उपचार के साथ समान रूप से अच्छी तरह से किया जा सकता है, जैसे कि "त्रुटि हुई" चारों ओर झंडे।
18

1

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

विचार करें:

try {
   // parse
} catch (NumberFormatException nfe){
   throw new RuntimeException("Could not parse as a Float: [" + myString + 
                              "] found at index: " + i, nfe);
} 

आवश्यकता के समय में आप वास्तव में इस तरह की अधिक जानकारी के साथ एक अपवाद की सराहना करेंगे।


हां, यह एक मान्य बिंदु है। मेरे मामले में मैं एक फ़ाइल से पढ़ रहा हूं, इसलिए मुझे वास्तव में वह स्ट्रिंग चाहिए जो पार्स करने में विफल रही। इसलिए मैंने एक और अपवाद को फेंकने के बजाय System.out.println (ex) किया (मैं कानूनी रूप से फ़ाइल के जितना पार्स करना चाहता हूं)।
माइकल मायर्स

1

0.02cअपवाद की स्थिति से निपटने की स्थिति की सामान्य समस्या को देखते हुए मुझे अपने दो प्रतिस्पर्धी विचारों को जोड़ना पसंद है :

  1. "व्यापक" try-catchब्लॉक की जिम्मेदारी (यानी आपके मामले में लूप के बाहर) का मतलब है कि कुछ बाद के बिंदु पर कोड बदलते समय, आप गलती से एक पंक्ति जोड़ सकते हैं जो आपके मौजूदा catchब्लॉक द्वारा नियंत्रित की जाती है ; संभवतः अनायास ही। आपके मामले में, इसकी संभावना कम है क्योंकि आप स्पष्ट रूप से एक को पकड़ रहे हैंNumberFormatException

  2. "संकरा" try-catchब्लॉक की जिम्मेदारी , अधिक कठिन रीफैक्टरिंग बन जाती है। विशेष रूप से जब (आपके मामले में) आप catchब्लॉक ( return nullबयान) के भीतर से एक "गैर-स्थानीय" निर्देश निष्पादित कर रहे हैं ।


1

यह विफलता से निपटने पर निर्भर करता है। यदि आप त्रुटि तत्वों को छोड़ना चाहते हैं, तो अंदर की कोशिश करें:

for(int i = 0; i < max; i++) {
    String myString = ...;
    try {
        float myNum = Float.parseFloat(myString);
        myFloats[i] = myNum;
    } catch (NumberFormatException ex) {
        --i;
    }
}

किसी भी अन्य मामले में मैं बाहर की कोशिश पसंद करूंगा। कोड अधिक पठनीय है, यह अधिक साफ है। हो सकता है कि अशक्त लौटते समय त्रुटि मामले में IllegalArgumentException को फेंकना बेहतर होगा।


1

मैं अपना $ 0.02 लगाऊंगा। कभी-कभी आपको अपने कोड में "अंत में" जोड़ने की आवश्यकता होती है (क्योंकि जो कभी भी अपना कोड पूरी तरह से पहली बार लिखते हैं?)। उन मामलों में, अचानक यह अधिक समझ में आता है कि लूप के बाहर की कोशिश / पकड़ है। उदाहरण के लिए:

try {
    for(int i = 0; i < max; i++) {
        String myString = ...;
        float myNum = Float.parseFloat(myString);
        dbConnection.update("MY_FLOATS","INDEX",i,"VALUE",myNum);
    }
} catch (NumberFormatException ex) {
    return null;
} finally {
    dbConnection.release();  // Always release DB connection, even if transaction fails.
}

क्योंकि यदि आपको कोई त्रुटि मिलती है, या नहीं, तो आप केवल एक बार अपने डेटाबेस कनेक्शन (या अपने पसंदीदा प्रकार के अन्य संसाधन ...) को जारी करना चाहते हैं।


1

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

यदि विधि "बाहरी (") कॉल विधि "इनर ()" (जो स्वयं को पुनरावर्ती कह सकती है), यदि संभव हो तो विधि "आउटर ()" में ट्राई-कैच का पता लगाने का प्रयास करें। एक सरल "स्टैक क्रैश" उदाहरण जो हम एक प्रदर्शन वर्ग में उपयोग करते हैं, लगभग 6,400 फ्रेम में विफल रहता है जब कोशिश-कैच आंतरिक विधि में होता है, और लगभग 11,600 पर जब यह बाहरी विधि में होता है।

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


0

यदि आप प्रत्येक पुनरावृत्ति के लिए अपवाद को पकड़ना चाहते हैं, या यह जाँचना चाहते हैं कि किस अपवाद को फेंक दिया गया है और प्रत्येक अपवाद को एक पुनरावृत्ति में पकड़ते हैं, तो कोशिश करें ... लूप के अंदर पकड़ें। यदि अपवाद होता है, तो यह लूप को नहीं तोड़ेगा और आप लूप में प्रत्येक पुनरावृत्ति में प्रत्येक अपवाद को पकड़ सकते हैं।

यदि आप लूप को तोड़ना चाहते हैं और जब भी फेंकना अपवाद की जांच करना चाहते हैं, तो कोशिश करें ... लूप से बाहर निकलें। यह लूप को तोड़ देगा और कैच (यदि कोई हो) के बाद स्टेटमेंट निष्पादित करेगा।

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

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