2011-12-24 15 views
47

वहाँ एक ट्राई/कैच ब्लॉक का उपयोग करने के लिए जावा में किसी भी भूमि के ऊपर, के रूप में एक करने का विरोध किया है, तो ब्लॉक (यह सोचते हैं कि संलग्न कोड अन्यथा इतना अनुरोध नहीं करता)?जावा अगर बनाम कोशिश/पकड़ भूमि के ऊपर

public String tryTrim(String raw) { 
    try { 
     return raw.trim(); 
    } catch (Exception e) { 
    } 
    return null; 
} 

public String ifTrim(String raw) { 
    if (raw == null) { 
     return null; 
    } 
    return raw.trim(); 
} 

raw इनपुट केवल शायद ही कभी null है, तो वहाँ दो तरीकों के बीच किसी भी प्रदर्शन अंतर है:

उदाहरण के लिए, तार के लिए एक "सुरक्षित ट्रिम" विधि के निम्नलिखित दो सरल कार्यान्वयन ले ?

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

उदाहरण के लिए, यह एक आम मामला है N parameters के साथ एक विधि है, जो अपने शुरू के निकट उनमें से M <= N का उपयोग करता है, जल्दी और निर्धारणात्मक में नाकाम रहने के "अवैध" (जैसे, एक शून्य या खाली स्ट्रिंग) अगर किसी भी तरह के पैरामीटर है है, शेष कोड को प्रभावित किए बिना।

ऐसे मामलों में, बजाय k * Mलिखने के लिए होने का अगर ब्लॉक, एक ट्राई/कैच ब्लॉक काफी छोटा है (जहां k पैरामीटर प्रति चेकों की औसत संख्या, जैसे शून्य या खाली स्ट्रिंग के लिए k = 2 है) कोड और एक 1-2 पंक्ति टिप्पणी का उपयोग "अपरंपरागत" तर्क को स्पष्ट रूप से नोट करने के लिए किया जा सकता है।

इस तरह का एक पैटर्न विधि को भी तेज करेगा, विशेष रूप से यदि त्रुटि की स्थिति शायद ही कभी होती है, और यह प्रोग्राम सुरक्षा समझौता किए बिना ऐसा करेगी (मान लीजिए कि त्रुटि की स्थिति "सामान्य" है, उदाहरण के लिए एक स्ट्रिंग प्रोसेसिंग विधि में शून्य या खाली मान स्वीकार्य हैं, यद्यपि शायद ही कभी उपस्थिति में)।

उत्तर

52

मुझे पता है कि आप प्रदर्शन ओवरहेड के बारे में पूछ रहे हैं, लेकिन आपको वास्तव में try/catch और if का उपयोग नहीं करना चाहिए।

try/catch ऐसी चीजों के लिए है जो आपके नियंत्रण से बाहर हैं और सामान्य कार्यक्रम प्रवाह में नहीं हैं। उदाहरण के लिए, फ़ाइल और फ़ाइल सिस्टम को लिखने की कोशिश कर रहा है? उस स्थिति को आमतौर पर try/catch के साथ संभाला जाना चाहिए।

if कथन सामान्य प्रवाह और सामान्य त्रुटि जांच होना चाहिए। तो, उदाहरण के लिए, उपयोगकर्ता एक आवश्यक इनपुट फ़ील्ड को पॉप्युलेट करने में विफल रहता है? इसके लिए if का उपयोग करें, try/catch पर नहीं।

ऐसा लगता है कि आपका उदाहरण कोड दृढ़ता से सुझाव देता है कि सही दृष्टिकोण if कथन है और try/catch नहीं है।

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

+0

सही और, जैसा सर्गेई का जवाब इंगित करता है, अपवाद कभी नहीं फेंक दिया गया है, भले ही अधिक ओवरहेड हो। धन्यवाद! – PNS

+3

@PNS सच नहीं है, सर्जी सिर्फ यह माप नहीं रही है कि आप और सर्गी को लगता है कि वह क्या माप रहा है (ओह मुझे वह वाक्य पसंद है, माफ करना विरोध नहीं कर सकता;))। यदि आप कैच ब्लॉक में अपवाद नहीं लेते हैं तो कोई ओवरहेड नहीं है। लेकिन फिर जेआईटी द्वारा एक नलपोइंटर चेक आम तौर पर नि: शुल्क है (स्पष्ट जांच न करें और इसके बजाय एचडब्ल्यू अपवाद को पकड़ें) ताकि यह इस बात पर निर्भर करता है कि जेआईटी इस स्थिति में अनुकूलन करने के लिए पर्याप्त बुद्धिमान है या नहीं। मामूली विचार नहीं, लेकिन वैसे भी अंतर चक्र चक्रों में मापा जाता है - बिल्कुल अनैच्छिक। – Voo

+0

जब आपने अपना जोड़ा तो मैं उस टिप्पणी को संपादित कर रहा था। तो, क्या आपको लगता है कि कम से कम सूर्य जेडीके में कोई अपवाद नहीं है (या सिर्फ एक नलपॉन्टर अपवाद) फेंक दिया गया है? – PNS

9

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

विषय पर रहते हुए, Exception यहां न पकड़ें, और विशेष रूप से इसे निगलें नहीं। आपके मामले में, आप NullPointerException की अपेक्षा करेंगे। यदि आप कुछ पकड़ना चाहते थे, तो आप यही पकड़ लेंगे (लेकिन पैराग्राफ पर वापस जाएं, यह करें)। जब आप पकड़ते हैं (और निगलते हैं!) Exception, आप कह रहे हैं "कोई फर्क नहीं पड़ता कि क्या गलत है, मैं इसे संभाल सकता हूं। मुझे परवाह नहीं है कि यह क्या है।" आपका प्रोग्राम एक अपरिवर्तनीय स्थिति में हो सकता है! केवल उस चीज़ को पकड़ें जिसे आप सौदा करने के लिए तैयार हैं, इसके साथ सौदा कर सकते हैं, भले ही वह परत शीर्ष परत हो और यह सब अपवाद लॉग करे और फिर निकास स्विच दबाएं।

+0

+1 में होने से पहले अपवादों को संभालने के लिए यह सस्ता है। यह वास्तव में वास्तव में बुरा अभ्यास है। –

+0

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

4

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

-3

जहां तक ​​भूमि के ऊपर चला जाता है के रूप में, आप अपने आप के लिए परीक्षण कर सकते हैं:।

संख्या

public class Overhead { 

public static void main(String[] args) { 
    String testString = ""; 

    long startTimeTry = System.nanoTime(); 
    tryTrim(testString); 
    long estimatedTimeTry = System.nanoTime() - startTimeTry; 

    long startTimeIf = System.nanoTime(); 
    ifTrim(testString); 
    long estimatedTimeIf = System.nanoTime() - startTimeIf; 

    System.out.println("Try time:" + estimatedTimeTry); 
    System.out.println("If time:" + estimatedTimeIf); 

} 

public static String tryTrim(String raw) { 
    try { 
     return raw.trim(); 
    } catch (Exception e) { 
    } 
    return null; 
} 

public static String ifTrim(String raw) { 
    if (raw == null) { 
     return null; 
    } 
    return raw.trim(); 
} 

} मैं कर रहे हैं मिल गया:

Try time:8102 
If time:1956 

जहां तक ​​शैली - यह एक अलग सवाल है। यदि कथन बहुत प्राकृतिक दिखता है, लेकिन कोशिश कई कारणों से वास्तव में अजीब लगती है: - आपने अपवाद को पकड़ा है, भले ही आप नल मान की जांच कर रहे हों, क्या आप कुछ "असाधारण" होने की उम्मीद कर रहे हैं (अन्यथा NullException पकड़ें)? - आपने उस अपवाद को पकड़ा, क्या आप इसकी रिपोर्ट करने या निगलने जा रहे हैं? इत्यादि आदि

संपादित करें: यह मेरी टिप्पणी देखें कि यह एक अवैध परीक्षण क्यों है, लेकिन मैं वास्तव में यहां यह खड़ा नहीं छोड़ना चाहता था। बस tryTrim और ifTrim स्वैप करके, हम अचानक निम्न परिणाम (मेरी मशीन पर) मिलती है:

Try time:2043 
If time:6810 
इसके बजाय यह सब समझाने के लिए शुरू करने की

, तो बस एक शुरुआत के लिए this पढ़ें - क्लिफ के बारे में भी कुछ महान स्लाइड है पूरा विषय, लेकिन मुझे इस समय लिंक नहीं मिल रहा है।

हॉटस्पॉट में अपवाद हैंडलिंग कैसे काम करता है, मुझे पता है कि एक सही परीक्षण में अपवाद के बिना प्रयास/पकड़ना) आधारभूत प्रदर्शन होगा (क्योंकि वहां कोई ओवरहेड नहीं है), लेकिन जेआईटी कुछ चालें खेल सकता है विधि आमंत्रण के बाद नलपोइंटर चेक (कोई स्पष्ट जांच नहीं है, लेकिन ऑब्जेक्ट शून्य होने पर एचडब्ल्यू अपवाद पकड़ें) इस मामले में हमें एक ही परिणाम मिल जाएगा। यह भी मत भूलना: हम आसानी से अनुमानित अंतर के बारे में बात कर रहे हैं यदि एक सीपीयू चक्र होगा! ट्रिम कॉल का दस लाख गुना खर्च होगा।

+4

मुझे उम्मीद है कि यहां कोई भी मानता है कि परीक्षण सही है? हमारे पास कक्षा लोडिंग की समस्याएं हैं, टाइमर त्रुटियों (टाइमर के लिए आपकी डिफ़ॉल्ट सटीकता 10-15ms है, अब केवल एक सेकंड के लिए सोचें जो हमें बताती है), गैर-जब्त कोड का परीक्षण करें और इसी तरह। जावा में माइक्रो बेंचमार्क सही होने के लिए मुश्किल हैं, लेकिन यह संकलित भाषा में भी समझ में नहीं आता है ... – Voo

+0

मैंने कुछ अन्य पोस्टों में पढ़ा है जो कोशिश करते हैं/पकड़ते हैं, जैसे ही ओवरहेड के बारे में है, बशर्ते कि कोई अपवाद नहीं था फेंक दिया, लेकिन स्पष्ट रूप से यह मामला नहीं है, अकेले "पैटर्न शुद्धता" मुद्दों को छोड़ दें। बेशक, परीक्षण में मापा गया मान मान 2 अलग-अलग ब्लॉक के लिए कंपाइलर सेटअप समय का प्रभुत्व है, जिसे आम तौर पर अधिक वास्तविक दुनिया परिदृश्यों में संलग्न कोड चलने वाले समय से नगण्य बना दिया जाएगा, लेकिन यह अभी भी एक बिंदु बनाता है। – PNS

+1

@PNS बस अगर स्वैप करें और ब्लॉक का प्रयास करें और अचानक मेरे लिए अगर 4Times तेज है तो कोशिश करें .. – Voo

28

यह सवाल लगभग कर दिया गया "मौत का जवाब" है, लेकिन मुझे लगता है कि कुछ अधिक अंक कि उपयोगी बनाया जा सकता है कर रहे हैं:

  • गैर असाधारण नियंत्रण प्रवाह के लिए try/catch का उपयोग करना (बुरा शैली है में जावा)। (अक्सर क्या "गैर असाधारण" का अर्थ है के बारे में बहस कर रहा है ... लेकिन यह एक अलग विषय है।) कारण के

  • भाग यह बुरा है शैली है कि try/catch परिमाण के आदेश अधिक एक नियमित रूप से की तुलना में महंगा है नियंत्रण प्रवाह विवरण । वास्तविक अंतर कार्यक्रम और मंच पर निर्भर करता है, लेकिन मुझे उम्मीद है कि यह 1000 या अधिक बार महंगा होगा। अन्य चीजों के अलावा, निर्माण अपवाद ऑब्जेक्ट एक स्टैक ट्रेस कैप्चर करता है, जो स्टैक पर प्रत्येक फ्रेम के बारे में जानकारी को देखता है और कॉपी करता है। गहरा ढेर है, जितना अधिक कॉपी करने की जरूरत है।

  • खराब शैली के कारण का एक और हिस्सा यह है कि कोड पढ़ने के लिए कठिन है।

1 - जावा 7 के हाल के संस्करणों में JIT अपवाद काफी, ओवरहेड्स कम करने के लिए कुछ मामलों में से निपटने का अनुकूलन कर सकते हैं। हालांकि, इन अनुकूलन डिफ़ॉल्ट रूप से सक्षम नहीं हैं। ,

  • पकड़ने Exception बहुत बुरा व्यवहार है एक मौका है कि आप दुर्घटना से अन्य अनियंत्रित अपवाद पकड़ेगा क्योंकि वहाँ:

    जिस तरह से है कि आप उदाहरण के लिखे से मुद्दों को भी कर रहे हैं। उदाहरण के लिए, यदि आपने raw.substring(1) पर कॉल के आसपास ऐसा किया है तो आप संभावित StringIndexOutOfBoundsException एस भी पकड़ लेंगे ... और बग छुपाएं।

  • आपका उदाहरण क्या करने का प्रयास कर रहा है (संभवतः) null तारों से निपटने में खराब अभ्यास का परिणाम है। एक सामान्य सिद्धांत के रूप में, आपको null स्ट्रिंग्स के उपयोग को कम करने की कोशिश करनी चाहिए, और अपने (जानबूझकर) प्रसार को सीमित करने का प्रयास करना चाहिए। जहां संभव हो, null के बजाय "कोई मान नहीं" के बजाय खाली स्ट्रिंग का उपयोग करें। और जब आपके पास ऐसा कोई मामला है जहां null स्ट्रिंग को पास करने या वापस करने के लिए आवश्यक है, तो इसे स्पष्ट रूप से अपनी विधि javadocs में दस्तावेज़ करें। यदि आपकी विधियों को null के साथ कॉल किया जाता है, तो उन्हें नहीं चाहिए ... यह एक बग है। इसे अपवाद फेंक दें। null लौटकर (इस उदाहरण में) द्वारा बग की क्षतिपूर्ति करने की कोशिश न करें।


अनुसरण करे

मेरा प्रश्न है, और अधिक सामान्य था न केवल शून्य मान के लिए।

... और मेरे उत्तर में अधिकांश बिंदु शून्य मानों के बारे में नहीं हैं!

लेकिन कृपया ध्यान रखें कि ऐसे कई मामले हैं जहां आप कभी-कभी शून्य मूल्य, या कोई अन्य मूल्य जो अपवाद उत्पन्न कर सकते हैं, और केवल उन्हें अनदेखा कर सकते हैं। यह मामला है, उदाहरण के लिए, जब कहीं से कुंजी/जोड़ी मान पढ़ते हैं और उन्हें tryTrim() ऊपर की तरह एक विधि में पास करते हैं।

हां ऐसी स्थितियां हैं जहां null मूल्यों की अपेक्षा की जाती है, और आपको उनके साथ सौदा करने की आवश्यकता है।

लेकिन मैं तर्क दूंगा कि tryTrim() क्या कर रहा है (आमतौर पर) null से निपटने का गलत तरीका है। कोड के इन तीन टुकड़े की तुलना करें:

// Version 1 
String param = httpRequest.getParameter("foo"); 
String trimmed = tryTrim(param); 
if (trimmed == null) { 
    // deal with case of 'foo' parameter absent 
} else { 
    // deal with case of 'foo' parameter present 
} 

// Version 2 
String param = httpRequest.getParameter("foo"); 
if (param == null) { 
    // deal with case of 'foo' parameter absent 
} else { 
    String trimmed = param.trim(); 
    // deal with case of 'foo' parameter present 
} 

// Version 3 
String param = httpRequest.getParameter("foo"); 
if (param == null) { 
    // treat missing and empty parameters the same 
    param = ""; 
} 
String trimmed = param.trim(); 

अंत में आप एक नियमित स्ट्रिंग से अलग ढंग से null से निपटने के लिए, और यह आमतौर पर एक अच्छा विचार यह जितनी जल्दी हो सके करना है। null को इसके बिंदु मूल से प्रचारित करने की अनुमति है, अधिक संभावना है कि प्रोग्रामर भूल जाएगा कि null मान एक संभावना है, और एक गैर-शून्य मान मानते हुए बग्गी कोड लिखें। और भूल रहा है कि एक HTTP अनुरोध पैरामीटर गुम हो सकता है (यानी param == null) एक क्लासिक केस है जहां यह होता है।

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

+0

मेरा प्रश्न न केवल सामान्य मूल्यों के लिए अधिक सामान्य था। लेकिन कृपया ध्यान रखें कि ऐसे कई मामले हैं जहां आप कभी-कभी शून्य मूल्य, या कोई अन्य मूल्य जो अपवाद उत्पन्न कर सकते हैं, और केवल उन्हें अनदेखा कर सकते हैं। यह मामला है, उदाहरण के लिए, जब कहीं से कुंजी/जोड़ी मान पढ़ते हैं और उन्हें tryTrim() ऊपर की तरह एक विधि में पास करते हैं। – PNS

+0

आपकी अनुवर्ती टिप्पणियां निश्चित रूप से समझ में आती हैं, क्योंकि हर किसी ने कोशिश की है कि tryTrim() के "पैटर्न शुद्धता" मुद्दे को इंगित किया गया है, और तर्क को आगे बढ़ाने के लिए धन्यवाद। मैंने इस मामले को प्रस्तुत करने के लिए प्रश्न संपादित किया है जहां tryTrim() आकर्षक लग सकता है (हालांकि अपरंपरागत)। – PNS

+0

पुराना उत्तर, लेकिन अभी भी प्रासंगिक है। चीजों को परिप्रेक्ष्य में रखने के लिए, मैं यह इंगित करना चाहता हूं कि इस उद्देश्य के लिए खाली तारों में "तार" नल तारों को वास्तव में [शून्य ऑब्जेक्ट पैटर्न] के एक अभिव्यक्ति के रूप में देखा जा सकता है (https://en.wikipedia.org/ wiki/Null_Object_pattern)। यह दिलचस्प है क्योंकि अब आपके पास इसका उपयोग कब और कब नहीं करना है, यह तय करने के लिए आपके पास अधिक सामान्य दिशानिर्देश हैं। – tne