दूसरों ने संक्षेप में बताया है कि क्यों जल्दी फेंकना है । मुझे इसके बजाय देर से भाग को पकड़ने के लिए ध्यान केंद्रित करने दें , जिसके लिए मैंने अपने स्वाद के लिए संतोषजनक स्पष्टीकरण नहीं देखा है।
क्यों अपवाद हैं?
इस बात को लेकर काफी भ्रम है कि अपवाद पहले स्थान पर क्यों हैं। मुझे यहां बड़ा रहस्य साझा करने दें: अपवादों और अपवादों से निपटने का कारण ... ABSTRACTION ।
क्या आपने इस तरह कोड देखा है:
static int divide(int dividend, int divisor) throws DivideByZeroException {
if (divisor == 0)
throw new DivideByZeroException(); // that's a checked exception indeed
return dividend / divisor;
}
static void doDivide() {
int a = readInt();
int b = readInt();
try {
int res = divide(a, b);
System.out.println(res);
} catch (DivideByZeroException e) {
// checked exception... I'm forced to handle it!
System.out.println("Nah, can't divide by zero. Try again.");
}
}
यही नहीं अपवादों का उपयोग कैसे किया जाना चाहिए। उपरोक्त जैसे कोड वास्तविक जीवन में मौजूद हैं, लेकिन वे एक विपथन के अधिक हैं, और वास्तव में अपवाद (दंड) हैं। उदाहरण के लिए विभाजन की परिभाषा , यहां तक कि शुद्ध गणित में, सशर्त है: यह हमेशा "कॉलर कोड" होता है जिसे इनपुट डोमेन को प्रतिबंधित करने के लिए शून्य के असाधारण मामले को संभालना पड़ता है। यह बदसूरत है। यह हमेशा फोन करने वाले के लिए दर्द होता है। फिर भी, इस तरह की स्थितियों के लिए चेक- टू -डू पैटर्न जाना स्वाभाविक तरीका है:
static int divide(int dividend, int divisor) {
// throws unchecked ArithmeticException for 0 divisor
return dividend / divisor;
}
static void doDivide() {
int a = readInt();
int b = readInt();
if (b != 0) {
int res = divide(a, b);
System.out.println(res);
} else {
System.out.println("Nah, can't divide by zero. Try again.");
}
}
वैकल्पिक रूप से, आप इस तरह OOP शैली पर पूर्ण कमांडो जा सकते हैं:
static class Division {
final int dividend;
final int divisor;
private Division(int dividend, int divisor) {
this.dividend = dividend;
this.divisor = divisor;
}
public boolean check() {
return divisor != 0;
}
public int eval() {
return dividend / divisor;
}
public static Division with(int dividend, int divisor) {
return new Division(dividend, divisor);
}
}
static void doDivide() {
int a = readInt();
int b = readInt();
Division d = Division.with(a, b);
if (d.check()) {
int res = d.eval();
System.out.println(res);
} else {
System.out.println("Nah, can't divide by zero. Try again.");
}
}
जैसा कि आप देखते हैं, कॉलर कोड में प्री-चेक का बोझ होता है, लेकिन इसके बाद कोई अपवाद हैंडलिंग नहीं करता है। यदि ArithmeticException
कभी कोई कॉलिंग से आता है divide
या करता है eval
, तो यह आप ही हैं, जिसे अपवाद हैंडलिंग करना है और अपना कोड ठीक करना है, क्योंकि आप भूल गए हैं check()
। इसी तरह के कारणों के लिए एक पकड़ना NullPointerException
लगभग हमेशा गलत काम है।
अब कुछ लोग हैं जो कहते हैं कि वे विधि / फ़ंक्शन हस्ताक्षर में असाधारण मामलों को देखना चाहते हैं, अर्थात आउटपुट डोमेन को स्पष्ट रूप से विस्तारित करना चाहते हैं । वे ऐसे हैं जो अपवादों की जाँच करते हैं । बेशक, आउटपुट डोमेन को बदलने से किसी भी प्रत्यक्ष कॉलर कोड को अनुकूलित करने के लिए मजबूर होना चाहिए, और यह वास्तव में चेक किए गए अपवादों के साथ हासिल किया जाएगा। लेकिन आपको इसके लिए अपवादों की आवश्यकता नहीं है! यही कारण है कि आपके पास Nullable<T>
सामान्य कक्षाएं , केस क्लासेस , बीजीय डेटा प्रकार और यूनियन प्रकार हैं । कुछ ओओ लोग इस तरह की साधारण त्रुटि के मामलों में भी वापसी करना पसंद कर सकते हैंnull
:
static Integer divide(int dividend, int divisor) {
if (divisor == 0) return null;
return dividend / divisor;
}
static void doDivide() {
int a = readInt();
int b = readInt();
Integer res = divide(a, b);
if (res != null) {
System.out.println(res);
} else {
System.out.println("Nah, can't divide by zero. Try again.");
}
}
तकनीकी रूप से अपवाद का उपयोग उपरोक्त उद्देश्य के लिए किया जा सकता है, लेकिन यहां बिंदु यह है कि ऐसे उपयोग के लिए अपवाद मौजूद नहीं हैं । अपवाद समर्थक अमूर्तता हैं। अपवाद अप्रत्यक्ष के बारे में हैं। अपवाद प्रत्यक्ष ग्राहक अनुबंधों को तोड़ने के बिना "परिणाम" डोमेन को विस्तारित करने की अनुमति देते हैं , और त्रुटि हैंडलिंग "कहीं और" से निपटने के लिए। यदि आपका कोड अपवाद है, जो एक ही कोड के प्रत्यक्ष कॉलर्स में संभाला जाता है, बीच में अमूर्त की कोई परत के बिना, तो आप इसे गलत कर रहे हैं
कैच लेट कैसे करें?
तो हम यहाँ हैं। मैंने अपने तरीके से यह दिखाने के लिए तर्क दिया है कि उपरोक्त परिदृश्यों में अपवादों का उपयोग करना अपवाद नहीं है। हालांकि एक वास्तविक उपयोग मामला मौजूद है, जहां अपवाद से निपटने की पेशकश की गई अमूर्तता और अप्रत्यक्षता अपरिहार्य है। इस तरह के उपयोग को समझने से कैच लेट सिफारिश को भी समझने में मदद मिलेगी ।
इस मामले का उपयोग है: संसाधन के खिलाफ प्रोग्रामिंग ...
हां, व्यापारिक तर्क को अमूर्तता के खिलाफ प्रोग्राम किया जाना चाहिए , न कि ठोस कार्यान्वयन। शीर्ष स्तर IOC "वायरिंग" कोड संसाधन अमूर्तता के ठोस कार्यान्वयन को तुरंत रोक देगा, और उन्हें व्यावसायिक तर्क के लिए नीचे पारित करेगा। यहां कुछ भी नया नहीं है। लेकिन उन संसाधनों के अमूर्त के ठोस कार्यान्वयन संभवतः अपने स्वयं के कार्यान्वयन विशिष्ट अपवादों को फेंक सकते हैं , क्या वे नहीं कर सकते हैं?
तो उन कार्यान्वयन विशिष्ट अपवादों को कौन संभाल सकता है? क्या व्यापार तर्क में किसी भी संसाधन विशिष्ट अपवाद को संभालना संभव है? नहीं, यह नहीं है। व्यापार तर्क को अमूर्तता के खिलाफ क्रमादेशित किया जाता है, जो उन कार्यान्वयन विशिष्ट अपवाद विवरणों के ज्ञान को बाहर करता है।
"अहा!", आप कह सकते हैं: "लेकिन इसीलिए हम अपवादों को तोड़ सकते हैं और अपवाद पदानुक्रम बना सकते हैं" ( मिस्टर स्प्रिंग की जाँच करें !)। मैं आपको बता दूं, यह एक पतन है। सबसे पहले, ओओपी पर प्रत्येक उचित पुस्तक कहती है कि ठोस विरासत खराब है, फिर भी किसी तरह जेवीएम का यह मुख्य घटक, अपवाद हैंडलिंग, कंक्रीट विरासत के साथ निकटता से जुड़ा हुआ है। विडंबना यह है कि जोशुआ बलोच अपनी प्रभावी जावा पुस्तक लिख नहीं सकते थे इससे पहले कि वह एक काम कर रहे जेवीएम के साथ अनुभव प्राप्त कर सकें, क्या वह कर सकते थे? यह अगली पीढ़ी के लिए "सबक सीखा" पुस्तक से अधिक है। दूसरी बात, और इससे भी महत्वपूर्ण बात यह है कि यदि आप एक उच्च-स्तरीय अपवाद को पकड़ते हैं तो आप इसे कैसे संभालेंगे?PatientNeedsImmediateAttentionException
: क्या हमें उसे एक गोली देनी है या उसके पैर काटना है !? सभी संभावित उपवर्गों पर एक स्विच स्टेटमेंट के बारे में कैसे? वहां तुम्हारा बहुरूपता जाता है, वहां अमूर्तता जाती है। सही पकड़े हैं।
तो संसाधन विशिष्ट अपवादों को कौन संभाल सकता है? यह वह होना चाहिए जो समास जानता हो! जिस ने संसाधन को तुरंत बदल दिया! "वायरिंग" कोड बेशक! इसकी जांच करें:
व्यापार तर्क अमूर्तता के खिलाफ कोडित ... कोई परिणाम नहीं त्रुटि!
static interface InputResource {
String fetchData();
}
static interface OutputResource {
void writeData(String data);
}
static void doMyBusiness(InputResource in, OutputResource out, int times) {
for (int i = 0; i < times; i++) {
System.out.println("fetching data");
String data = in.fetchData();
System.out.println("outputting data");
out.writeData(data);
}
}
इस बीच कहीं और ठोस कार्यान्वयन ...
static class ConstantInputResource implements InputResource {
@Override
public String fetchData() {
return "Hello World!";
}
}
static class FailingInputResourceException extends RuntimeException {
public FailingInputResourceException(String message) {
super(message);
}
}
static class FailingInputResource implements InputResource {
@Override
public String fetchData() {
throw new FailingInputResourceException("I am a complete failure!");
}
}
static class StandardOutputResource implements OutputResource {
@Override
public void writeData(String data) {
System.out.println("DATA: " + data);
}
}
और अंत में वायरिंग कोड ... कंक्रीट संसाधन अपवादों को कौन संभालता है? जो उनके बारे में जानता है!
static void start() {
InputResource in1 = new FailingInputResource();
InputResource in2 = new ConstantInputResource();
OutputResource out = new StandardOutputResource();
try {
ReusableBusinessLogicClass.doMyBusiness(in1, out, 3);
}
catch (FailingInputResourceException e)
{
System.out.println(e.getMessage());
System.out.println("retrying...");
ReusableBusinessLogicClass.doMyBusiness(in2, out, 3);
}
}
अब मेरे साथ सहन करो। इसके बाद के संस्करण कोड है सरलीकृत। आप कह सकते हैं कि आपके पास आईओसी कंटेनर प्रबंधित संसाधनों के कई स्कोप के साथ एक एंटरप्राइज़ एप्लिकेशन / वेब कंटेनर है, और आपको सत्र के लिए स्वचालित पुनर्प्रयास और पुनर्संरचना या अनुरोध गुंजाइश संसाधनों आदि की आवश्यकता है। निचले स्तर के स्कोप पर तारों के तर्क को अमूर्त कारखानों को दिया जा सकता है। संसाधन बनाएं, इसलिए सटीक कार्यान्वयन के बारे में पता नहीं है। केवल उच्च स्तर के स्कोप्स को वास्तव में पता होगा कि उन निचले स्तर के संसाधनों को क्या अपवाद फेंक सकते हैं। अब पकड़ो!
दुर्भाग्य से, अपवाद केवल कॉल स्टैक पर अप्रत्यक्षता की अनुमति देते हैं, और उनके अलग-अलग कार्डिनैलिटी के साथ अलग-अलग स्कोप आमतौर पर कई अलग-अलग थ्रेड्स पर चलते हैं। अपवाद के साथ उस माध्यम से संवाद करने का कोई तरीका नहीं। हमें यहां कुछ और अधिक शक्तिशाली बनाने की जरूरत है। उत्तर: async संदेश गुजर रहा है । निचले स्तर के दायरे की जड़ में हर अपवाद को पकड़ो। किसी भी चीज को नजरअंदाज न करें, कुछ भी होने दें। यह वर्तमान स्कोप के कॉल स्टैक पर बनाए गए सभी संसाधनों को बंद और निपटान करेगा। फिर अपवाद हैंडलिंग दिनचर्या में संदेश क्वीज / चैनल का उपयोग करके स्कूप को उच्चतर संदेश भेजने के लिए प्रचारित करें, जब तक कि आप उस स्तर तक नहीं पहुंच जाते हैं, जहां पर समसामयिकी ज्ञात हो। वह लड़का है जो इसे संभालना जानता है।
सुम्मा सारांश
इसलिए मेरी व्याख्या के अनुसार सबसे सुविधाजनक जगह पर अपवादों को पकड़ने के लिए देर से पकड़ने का मतलब है, जहां आप किसी भी तरह से ब्रेकिंग नहीं कर रहे हैं । बहुत जल्दी पकड़ना नहीं है! उस परत पर अपवादों को पकड़ो जहां आप संसाधन सार के फेंकने वाले ठोस अपवाद बनाते हैं, वह परत जो अमूर्त तत्वों को जानती है। "वायरिंग" परत।
HTH। हैप्पी कोडिंग!