java - चेक अपवादों के खिलाफ मामला




exception checked-exceptions (20)

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

मैं वर्तमान में कुछ नया कोड लिख रहा हूं और अपवादों से निपटने के तरीके पर बहुत सावधानीपूर्वक ध्यान दे रहा हूं। मैं "हम अपवादों को पसंद नहीं करते" भीड़ के दृष्टिकोण को देखने की कोशिश कर रहा हूं और मैं अभी भी इसे नहीं देख सकता हूं।

मेरे द्वारा हर बातचीत में एक ही प्रश्न के साथ समाप्त हो गया है अनुत्तरित जा रहा है ... मुझे इसे सेट करने दें:

सामान्य रूप से (जावा कैसे डिजाइन किया गया था),

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

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

एक और आम तर्क जो मैंने सुना है वह है कि चेक अपवाद कोड को दोबारा प्रतिक्रिया देना कठिन बनाते हैं।

"मैं जो कुछ करने जा रहा हूं वह बाहर निकलना है" तर्क के लिए मैं कहता हूं कि यदि आप बाहर निकल रहे हैं तो आपको एक उचित त्रुटि संदेश प्रदर्शित करने की आवश्यकता है। यदि आप सिर्फ त्रुटियों को संभालने पर पंसद कर रहे हैं तो प्रोग्राम बहुत स्पष्ट नहीं होंगे जब कार्यक्रम स्पष्ट संकेत के बिना बाहर निकलता है।

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

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

सवाल यह है कि लोग कभी जवाब नहीं देते हैं:

यदि आप अपवाद उपclasses के बजाय RuntimeException subclasses फेंकते हैं तो आप कैसे जानते हैं कि आपको क्या पकड़ना है?

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

यदि आप थ्रोबल को पकड़ते हैं तो आप सिस्टम अपवादों और वीएम त्रुटियों (और इसी तरह) का इलाज कर रहे हैं। यह मेरे लिए गलत लगता है।

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

मैं कहूंगा कि एक प्रोग्राम जो स्टैक ट्रेस प्रदर्शित करता है वह गलत है। क्या लोग जो चेक अपवाद पसंद नहीं करते हैं, वे इस तरह महसूस नहीं करते हैं?

इसलिए, यदि आपको चेक अपवाद पसंद नहीं हैं तो क्या आप समझा सकते हैं कि क्यों नहीं उत्तर दें और उस प्रश्न का उत्तर दें जो उत्तर नहीं दिया गया है?

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


समस्या

The worst problem I see with exception handling mechanism is that it introduces code duplication in a big scale ! Let's be honest: In most of projects in 95% of the time all that developers really need to do with exception is to communicate it somehow to the user (and, in some cases, to the development team as well, eg by sending an e-mail with the stack trace). So usually the same line/block of code is used in every place the exception is handled.

Let's assume that we do simple logging in each catch block for some type of checked exception:

try{
   methodDeclaringCheckedException();
}catch(CheckedException e){
   logger.error(e);
}

If it's a common exception there may be even several hundreds of such try-catch blocks in a larger codebase. Now let's assume that we need to introduce popup dialog based exception handling instead of console logging or start to additionally send an e-mail to the development team.

Wait a moment... are we really going to edit all of that several hundreds of locations in the code?! You get my point :-).

समाधान

What we did to adress that issue was introducing the concept of exception handlers (to which I'll further refer as EH's) to centralize exception handling. To every class that needs to hande exceptions an instance of exception handler is injected by our Dependency Injection framework. So the typical pattern of exception handling now looks like this:

try{
    methodDeclaringCheckedException();
}catch(CheckedException e){
    exceptionHandler.handleError(e);
}

Now to customize our exception handling we only need to change the code in a single place (EH code).

Of course for more complex cases we can implement several subclasses of EHs and leverage features that our DI framework provides us. By changing our DI framework configuration we can easily switch EH implementation globally or provide specific implementations of EH to classes with special exception handling needs (for example using Guice @Named annotation).

That way we can differentiate exception handling behaviour in development and release version of application (eg. development - logging the error and halting the application, prod - logging the error with more details and letting the application continue its execution) with no effort.

Last one thing

Last but not least, it may seem that the same kind of centralisation can be obtained by just passing our exceptions "up" until they arrive to some top level exception handling class. But that leads to cluttering of code and signatures of our methods and introduces maintenance problems mentioned by others in this thread.


Exception categories

When talking about exceptions I always refer back to Eric Lippert's Vexing exceptions blog article. He places exceptions into these categories:

  • Fatal - These exceptions are not your fault : you cannot prevent then, and you cannot sensibly handle them. For example, OutOfMemoryError or ThreadAbortException .
  • Boneheaded - These exceptions are your fault : you should have prevented them, and they represent bugs in your code. For example, ArrayIndexOutOfBoundsException , NullPointerException or any IllegalArgumentException .
  • Vexing - These exceptions are not exceptional , not your fault, you cannot prevent them, but you'll have to deal with them. They are often the result of an unfortunate design decision, such as throwing NumberFormatException from Integer.parseInt instead of providing an Integer.tryParseInt method that returns a boolean false on parse failure.
  • Exogenous - These exceptions are usually exceptional , not your fault, you cannot (reasonably) prevent them, but you must handle them . For example, FileNotFoundException .

An API user:

  • must not handle fatal or boneheaded exceptions.
  • should handle vexing exceptions, but they should not occur in an ideal API.
  • must handle exogenous exceptions.

Checked exceptions

The fact that the API user must handle a particular exception is part of the method's contract between the caller and the callee. The contract specifies, among other things: the number and types of arguments the callee expects, the type of return value the caller can expect, and the exceptions the caller is expected to handle .

Since vexing exceptions should not exist in an API, only these exogenous exceptions must be checked exceptions to be part of the method's contract. Relatively few exceptions are exogenous , so any API should have relatively few checked exceptions.

A checked exception is an exception that must be handled . Handling an exception can be as simple as swallowing it. There! The exception is handled. Period. If the developer wants to handle it that way, fine. But he can't ignore the exception, and has been warned.

API problems

But any API that has checked vexing and fatal exceptions (eg the JCL) will put unnecessary strain on the API users. Such exceptions have to be handled, but either the exception is so common that it should not have been an exception in the first place, or nothing can be done when handling it. And this causes Java developers to hate checked exceptions.

Also, many APIs don't have a proper exception class hierarchy, causing all kinds of non-exogenous exception causes to be represented by a single checked exception class (eg IOException ). And this also causes Java developers to hate checked exceptions.

निष्कर्ष

Exogenous exceptions are those that are not your fault, could not have been prevented, and which should be handled. These form a small subset of all the exceptions that can get thrown. APIs should only have checked exogenous exceptions , and all other exceptions unchecked. This will make better APIs, put less strain on the API user, and therefore reduce the need to catch all, swallow or rethrow unchecked exceptions.

So don't hate Java and its checked exceptions. Instead, hate the APIs that overuse checked exceptions.


खैर, यह एक स्टैकट्रैक या चुपचाप दुर्घटनाग्रस्त होने के बारे में नहीं है। यह परतों के बीच त्रुटियों को संवाद करने में सक्षम होने के बारे में है।

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

मैं वास्तव में एक आवेदन में इस स्थिति से निपट रहा हूँ। हमने AppSpecificException के रूप में लगभग अपवादों को दोबारा बनाया। इसने हस्ताक्षर वास्तव में साफ किए और हमें हस्ताक्षर में फेंकने के बारे में चिंता करने की ज़रूरत नहीं थी।

बेशक, अब हमें उच्च स्तर पर त्रुटि प्रबंधन, पुनः प्रयास तर्क और कार्यान्वित करने की आवश्यकता है। सबकुछ AppSpecificException है, हालांकि, हम यह नहीं कह सकते कि "यदि IOException फेंक दिया गया है, पुनः प्रयास करें" या "यदि क्लास नॉटफाउंड फेंक दिया गया है, तो पूरी तरह से निरस्त करें"। हमारे पास असली अपवाद प्राप्त करने का एक विश्वसनीय तरीका नहीं है क्योंकि चीजें हमारे कोड और तृतीय-पक्ष कोड के बीच गुजरने के बाद बार-बार पुन: संग्रहित होती हैं।

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

मैंने पाया, समय और समय फिर से, और पूरे परियोजना में मैंने उल्लेख किया है कि अपवाद हैंडलिंग 3 श्रेणियों में आती है:

  1. एक विशिष्ट अपवाद पकड़ो और संभाल लें। उदाहरण के लिए, पुनः प्रयास तर्क लागू करना है।
  2. अन्य अपवादों को पकड़ो और पुनर्स्थापित करें। यहां जो कुछ भी होता है वह आम तौर पर लॉगिंग होता है, और आमतौर पर यह एक संक्षिप्त संदेश है जैसे "$ फ़ाइल नाम खोलने में असमर्थ"। ये त्रुटियां हैं जिनके बारे में आप कुछ भी नहीं कर सकते; केवल एक उच्च स्तर इसे संभालने के लिए पर्याप्त जानता है।
  3. सब कुछ पकड़ो और एक त्रुटि संदेश प्रदर्शित करें। यह आमतौर पर एक प्रेषक की जड़ पर होता है, और यह सब यह सुनिश्चित करता है कि यह कॉलर को गैर-अपवाद तंत्र (पॉपअप संवाद, आरपीसी त्रुटि ऑब्जेक्ट को मार्शल करना आदि) के माध्यम से त्रुटि को संवाद कर सकता है।

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

try {
  // do stuff
} catch (AnnoyingcheckedException e) {
  throw new RuntimeException(e);
}

99% समय मैं इसके बारे में कुछ भी नहीं कर सकता। अंत में ब्लॉक किसी भी आवश्यक सफाई (या कम से कम उन्हें चाहिए) करते हैं।

मैंने यह देखा है कि मैंने कितनी बार देखा है:

try {
  // do stuff
} catch (AnnoyingCheckedException e) {
  // do nothing
}

क्यूं कर? क्योंकि किसी को इसके साथ सौदा करना था और आलसी था। क्या यह गलत था? ज़रूर। क्या ऐसा होता है? पूर्ण रूप से। क्या होगा यदि यह इसके बजाय एक अनचेक अपवाद था? ऐप अभी मर गया होगा (जो एक अपवाद निगलने के लिए बेहतर है)।

और फिर हमारे पास क्रूर कोड है जो प्रवाह नियंत्रण के रूप में अपवादों का उपयोग करता है, जैसे java.text.Format करता है। Bzzzt। गलत। एक उपयोगकर्ता को "एबीसी" को किसी फॉर्म पर किसी फ़ील्ड में डालने वाला अपवाद नहीं है।

ठीक है, मुझे लगता है कि तीन कारण थे।


मुझे पता है कि यह एक पुराना सवाल है, लेकिन मैंने चेक अपवादों के साथ थोड़ी देर कुश्ती बिताई है और मेरे पास कुछ जोड़ने के लिए है। कृपया मुझे इसकी लंबाई के लिए क्षमा करें!

चेक अपवादों के साथ मेरा मुख्य गोमांस यह है कि वे बहुरूपता को बर्बाद कर देते हैं। पॉलिमॉर्फिक इंटरफेस के साथ उन्हें अच्छी तरह से खेलना असंभव है।

अच्छा ओल 'जावा List इंटरफेस लो। हमारे पास ArrayList और LinkedList जैसे सामान्य स्मृति-क्रियान्वयन हैं। हमारे पास कंकाल वर्ग AbstractList जो नई प्रकार की सूची तैयार करना आसान बनाता है। केवल पढ़ने योग्य सूची के लिए हमें केवल दो विधियों को लागू करने की आवश्यकता है: size() और get(int index)

यह उदाहरण WidgetList क्लास किसी फ़ाइल से टाइप Widget (दिखाया नहीं गया) की कुछ निश्चित-आकार वाली ऑब्जेक्ट्स को पढ़ता है:

class WidgetList extends AbstractList<Widget> {
    private static final int SIZE_OF_WIDGET = 100;
    private final RandomAccessFile file;

    public WidgetList(RandomAccessFile file) {
        this.file = file;
    }

    @Override
    public int size() {
        return (int)(file.length() / SIZE_OF_WIDGET);
    }

    @Override
    public Widget get(int index) {
        file.seek((long)index * SIZE_OF_WIDGET);
        byte[] data = new byte[SIZE_OF_WIDGET];
        file.read(data);
        return new Widget(data);
    }
}

परिचित List इंटरफ़ेस का उपयोग करके विजेट्स को उजागर करके, आप आइटम सूची ( list.get(123) ) पुनर्प्राप्त कर सकते हैं या for (Widget w : list) ... बारे में जानने के बिना for (Widget w : list) ... () के for (Widget w : list) ... एक सूची फिर से WidgetList कर सकते हैं। कोई भी इस सूची को जेनेरिक सूचियों का उपयोग करने वाले किसी भी मानक तरीकों से पास कर सकता है, या इसे Collections.synchronizedList में लपेट सकता है। कोड जो इसका उपयोग करता है, उसे न तो पता है और न ही इस बात पर ध्यान देना चाहिए कि "विजेट" स्पॉट पर बनाए गए हैं या नहीं, एक सरणी से आते हैं, या किसी फ़ाइल, या डेटाबेस, या नेटवर्क से या भविष्य के सबस्पेस रिले से पढ़े जाते हैं। यह अभी भी सही तरीके से काम करेगा क्योंकि List इंटरफेस सही ढंग से कार्यान्वित किया गया है।

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

स्पष्ट रूप से करने के लिए केवल एक चीज है अनचाहे अपवाद के रूप में चेक अपवादों को पकड़ और पुनर्स्थापित करना:

@Override
public int size() {
    try {
        return (int)(file.length() / SIZE_OF_WIDGET);
    } catch (IOException e) {
        throw new WidgetListException(e);
    }
}

public static class WidgetListException extends RuntimeException {
    public WidgetListException(Throwable cause) {
        super(cause);
    }
}

((संपादित करें: जावा 8 ने इस मामले के लिए एक UncheckedIOException क्लास जोड़ा है: आईओएक्सप्शन को IOException विधि सीमाओं में पकड़ने और पुनर्स्थापित करने के लिए। मेरे बिंदु को साबित करने का तरीका!))

तो अपवादों की जांच की गई बस इस तरह के मामलों में काम नहीं करते हैं । आप उन्हें फेंक नहीं सकते। एक डेटाबेस द्वारा समर्थित एक चालाक Map लिए, या java.util.Random कार्यान्वयन एक COM पोर्ट के माध्यम से क्वांटम एंट्रॉपी स्रोत से जुड़ा हुआ है। जैसे ही आप पॉलिमॉर्फिक इंटरफेस के कार्यान्वयन के साथ कुछ उपन्यास करने की कोशिश करते हैं, चेक अपवादों की अवधारणा विफल हो जाती है। लेकिन चेक अपवाद इतने भद्दा हैं कि वे अभी भी आपको शांति में नहीं छोड़ेंगे, क्योंकि आपको अभी भी निम्न स्तर के तरीकों से किसी को पकड़ना और हटाना है, कोड को छेड़छाड़ करना और स्टैक ट्रेस को अव्यवस्थित करना है।

मुझे लगता है कि सर्वव्यापी Runnable इंटरफेस को अक्सर इस कोने में समर्थित किया जाता है, अगर यह कुछ ऐसा करता है जो चेक अपवाद फेंकता है। यह अपवाद को फेंक नहीं सकता है, इसलिए यह सब कुछ कर सकते हैं एक रनटाइम RuntimeException रूप में पकड़ और rethrowing द्वारा कोड अव्यवस्थित है।

असल में, यदि आप हैक का सहारा लेते हैं तो आप अविकसित चेक अपवाद फेंक सकते हैं । रन समय पर JVM, चेक अपवाद नियमों की परवाह नहीं करता है, इसलिए हमें केवल संकलक को मूर्ख बनाना होगा। ऐसा करने का सबसे आसान तरीका जेनेरिकों का दुरुपयोग करना है। यह इसके लिए मेरी विधि है (क्लास नाम दिखाया गया है क्योंकि (जावा 8 से पहले) जेनेरिक विधि के लिए कॉलिंग सिंटैक्स में इसकी आवश्यकता है):

class Util {
    /**
     * Throws any {@link Throwable} without needing to declare it in the
     * method's {@code throws} clause.
     * 
     * <p>When calling, it is suggested to prepend this method by the
     * {@code throw} keyword. This tells the compiler about the control flow,
     * about reachable and unreachable code. (For example, you don't need to
     * specify a method return value when throwing an exception.) To support
     * this, this method has a return type of {@link RuntimeException},
     * although it never returns anything.
     * 
     * @param t the {@code Throwable} to throw
     * @return nothing; this method never returns normally
     * @throws Throwable that was provided to the method
     * @throws NullPointerException if {@code t} is {@code null}
     */
    public static RuntimeException sneakyThrow(Throwable t) {
        return Util.<RuntimeException>sneakyThrow1(t);
    }

    @SuppressWarnings("unchecked")
    private static <T extends Throwable> RuntimeException sneakyThrow1(
            Throwable t) throws T {
        throw (T)t;
    }
}

हुर्रे! इसका उपयोग करके हम बिना किसी गहराई से स्टैक को किसी भी गहराई तक फेंक सकते हैं, इसे बिना किसी RuntimeException में लपेटकर, और स्टैक ट्रेस को अव्यवस्थित किए बिना! "विजेटलिस्ट" उदाहरण का फिर से उपयोग करना:

@Override
public int size() {
    try {
        return (int)(file.length() / SIZE_OF_WIDGET);
    } catch (IOException e) {
        throw sneakyThrow(e);
    }
}

दुर्भाग्यवश, चेक अपवादों का अंतिम अपमान यह है कि संकलक आपको चेक अपवाद को पकड़ने से इनकार करने से इंकार कर देता है, अगर इसकी ग़लत राय में इसे फेंक दिया नहीं जा सका। (अनचेक अपवादों में यह नियम नहीं है।) चुपके से फेंकने वाले अपवाद को पकड़ने के लिए हमें यह करना है:

try {
    ...
} catch (Throwable t) { // catch everything
    if (t instanceof IOException) {
        // handle it
        ...
    } else {
        // didn't want to catch this one; let it go
        throw t;
    }
}

यह थोड़ा अजीब है, लेकिन प्लस साइड पर, यह एक चेक अपवाद निकालने के लिए कोड से थोड़ा सा सरल है जो RuntimeException में लपेटा गया था।

खुशी से, throw t; स्टेटमेंट यहां कानूनी है, भले ही t का प्रकार चेक किया गया हो, पकड़े गए अपवादों को पुनर्स्थापित करने के बारे में जावा 7 में जोड़े गए नियम के लिए धन्यवाद।

When checked exceptions meet polymorphism, the opposite case is also a problem: when a method is spec'd as potentially throwing a checked exception, but an overridden implementation doesn't. For example, the abstract class OutputStream 's write methods all specify throws IOException . ByteArrayOutputStream is a subclass that writes to an in-memory array instead of a true I/O source. Its overridden write methods cannot cause IOException s, so they have no throws clause, and you can call them without worrying about the catch-or-specify requirement.

Except not always. Suppose that Widget has a method for saving it out to a stream:

public void writeTo(OutputStream out) throws IOException;

Declaring this method to accept a plain OutputStream is the right thing to do, so it can be used polymorphically with all kinds of outputs: files, databases, the network, and so on. And in-memory arrays. With an in-memory array, however, there is a spurious requirement to handle an exception that can't actually happen:

ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
    someWidget.writeTo(out);
} catch (IOException e) {
    // can't happen (although we shouldn't ignore it if it does)
    throw new RuntimeException(e);
}

As usual, checked exceptions get in the way. If your variables are declared as a base type that has more open-ended exception requirements, you have to add handlers for those exceptions even if you know they won't occur in your application.

But wait, checked exceptions are actually so annoying, that they won't even let you do the reverse! Imagine you currently catch any IOException thrown by write calls on an OutputStream , but you want to change the variable's declared type to a ByteArrayOutputStream , the compiler will berate you for trying to catch a checked exception that it says cannot be thrown.

That rule causes some absurd problems. For example, one of the three write methods of OutputStream is not overridden by ByteArrayOutputStream . Specifically, write(byte[] data) is a convenience method that writes the full array by calling write(byte[] data, int offset, int length) with an offset of 0 and the length of the array. ByteArrayOutputStream overrides the three-argument method but inherits the one-argument convenience method as-is. The inherited method does exactly the right thing, but it includes an unwanted throws clause. That was perhaps an oversight in the design of ByteArrayOutputStream , but they can never fix it because it would break source compatibility with any code that does catch the exception -- the exception that has never, is never, and never will be thrown!

That rule is annoying during editing and debugging too. Eg, sometimes I'll comment out a method call temporarily, and if it could have thrown a checked exception, the compiler will now complain about the existence of the local try and catch blocks. So I have to comment those out too, and now when editing the code within, the IDE will indent to the wrong level because the { and } are commented out. Gah! It's a small complaint but it seems like the only thing checked exceptions ever do is cause trouble.

I'm nearly done. My final frustration with checked exceptions is that at most call sites , there's nothing useful you can do with them. Ideally when something goes wrong we'd have a competent application-specific handler that can inform the user of the problem and/or end or retry the operation as appropriate. Only a handler high up the stack can do this because it's the only one that knows the overall goal.

Instead we get the following idiom, which is rampant as a way to shut the compiler up:

try {
    ...
} catch (SomeStupidExceptionOmgWhoCares e) {
    e.printStackTrace();
}

In a GUI or automated program the printed message won't be seen. Worse, it plows on with the rest of the code after the exception. Is the exception not actually an error? Then don't print it. Otherwise, something else is going to blow up in a moment, by which time the original exception object will be gone. This idiom is no better than BASIC's On Error Resume Next or PHP's error_reporting(0);

Calling some kind of logger class is not much better:

try {
    ...
} catch (SomethingWeird e) {
    logger.log(e);
}

That is just as lazy as e.printStackTrace(); and still plows on with code in an indeterminate state. Plus, the choice of a particular logging system or other handler is application-specific, so this hurts code reuse.

But wait! There is an easy and universal way to find the application-specific handler. It's higher up the call stack (or it is set as the Thread's uncaught exception handler ). So in most places, all you need to do is throw the exception higher up the stack . Eg, throw e; । Checked exceptions just get in the way.

I'm sure checked exceptions sounded like a good idea when the language was designed, but in practice I've found them to be all bother and no benefit.


संक्षेप में:

Exceptions are an API design question. -- No more, no less.

The argument for checked exceptions:

To understand why checked exceptions might not be good thing, let's turn the question around and ask: When or why are checked exceptions attractive, ie why would you want the compiler to enforce declaration of exceptions?

The answer is obvious: Sometimes you need to catch an exception, and that is only possible if the code being called offers a specific exception class for the error that you are interested in.

Hence, the argument for checked exceptions is that the compiler forces programmers to declare which exceptions are thrown, and hopefully the programmer will then also document specific exception classes and the errors that cause them.

In reality though, ever too often a package com.acme only throws an AcmeException rather than specific subclasses. Callers then need to handle, declare, or re-signal AcmeExceptions , but still cannot be certain whether an AcmeFileNotFoundError happened or an AcmePermissionDeniedError .

So if you're only interested in an AcmeFileNotFoundError , the solution is to file a feature request with the ACME programmers and tell them to implement, declare, and document that subclass of AcmeException .

So why bother?

Hence, even with checked exceptions, the compiler cannot force programmers to throw useful exceptions. It is still just a question of the API's quality.

As a result, languages without checked exceptions usually do not fare much worse. Programmers might be tempted to throw unspecific instances of a general Error class rather than an AcmeException , but if they care at all about their API quality, they will learn to introduce an AcmeFileNotFoundError after all.

Overall, the specification and documentation of exceptions is not much different from the specification and documentation of, say, ordinary methods. Those, too, are an API design question, and if a programmer forgot to implement or export a useful feature, the API needs to be improved so that you can work with it usefully.

If you follow this line of reasoning, it should be obvious that the "hassle" of declaring, catching, and re-throwing of exceptions that is so common in languages like Java often adds little value.

It is also worth noting that the Java VM does not have checked exceptions -- only the Java compiler checks them, and class files with changed exception declarations are compatible at run time. Java VM security is not improved by checked exceptions, only coding style.


Here 's one argument against checked exceptions (from joelonsoftware.com):

The reasoning is that I consider exceptions to be no better than "goto's", considered harmful since the 1960s, in that they create an abrupt jump from one point of code to another. In fact they are significantly worse than goto's:

  • They are invisible in the source code. Looking at a block of code, including functions which may or may not throw exceptions, there is no way to see which exceptions might be thrown and from where. This means that even careful code inspection doesn't reveal potential bugs.
  • They create too many possible exit points for a function. To write correct code, you really have to think about every possible code path through your function. Every time you call a function that can raise an exception and don't catch it on the spot, you create opportunities for surprise bugs caused by functions that terminated abruptly, leaving data in an inconsistent state, or other code paths that you didn't think about.

A problem with checked exceptions is that exceptions are often attached to methods of an interface if even one implementation of that interface uses it.

Another problem with checked exceptions is that they tend to be misused. The perfect example of this is in java.sql.Connection 's close() method. It can throw a SQLException , even though you've already explicitly stated that you're done with the Connection. What information could close() possibly convey that you'd care about?

Usually, when I close() a connection * , it looks something like this:

try {
    conn.close();
} catch (SQLException ex) {
    // Do nothing
}

Also, don't get me started on the various parse methods and NumberFormatException... .NET's TryParse, which doesn't throw exceptions, is so much easier to use it's painful to have to go back to Java (we use both Java and C# where I work).

* As an additional comment, a PooledConnection's Connection.close() doesn't even close a connection, but you still have to catch the SQLException due to it being a checked exception.


Artima http://www.artima.com/intv/handcuffs.html with one of the architects of .NET, Anders Hejlsberg, which acutely covers the arguments against checked exceptions. A short taster:

The throws clause, at least the way it's implemented in Java, doesn't necessarily force you to handle the exceptions, but if you don't handle them, it forces you to acknowledge precisely which exceptions might pass through. It requires you to either catch declared exceptions or put them in your own throws clause. To work around this requirement, people do ridiculous things. For example, they decorate every method with, "throws Exception." That just completely defeats the feature, and you just made the programmer write more gobbledy gunk. That doesn't help anybody.


As folks have already stated, checked exceptions don't exist in Java bytecode. They are simply a compiler mechanism, not unlike other syntax checks. I see checked exceptions a lot like I see the compiler complaining about a redundant conditional: if(true) { a; } b; । That's helpful but I might have done this on purpose, so let me ignore your warnings.

The fact of the matter is, you aren't going to be able to force every programmer to "do the right thing" if you enforce checked exceptions and everyone else is now collateral damage who just hates you for the rule you made.

Fix the bad programs out there! Don't try to fix the language to not allow them! For most folks, "doing something about an exception" is really just telling the user about it. I can tell the user about an unchecked exception just as well, so keep your checked exception classes out of my API.


Despite having read the whole page, I still can't find a single reasonable argument against checked exceptions. Most people are instead talking about poor API design, either at some Java classes or at their own classes.

The only scenario where this feature may be annoying is prototiping. This could be solved by adding some mechanism to the language (for instance, some @supresscheckedexceptions annotation). But for regular programming, I think checked exceptions are a good thing.


I have been working with several developers in the last three years in relatively complex applications. We have a code base that uses Checked Exceptions quite often with proper error handling, and some other that doesn't.

So far, I have it found easier to work with the code base with Checked Exceptions. When I am using someone else's API, it is nice that I can see exactly what kind of error conditions I can expect when I call the code and handle them properly, either by logging, displaying or ignoring (Yes, there is valid cases for ignoring exceptions, such as a ClassLoader implementation). That gives the code I am writing an opportunity to recover. All runtime exceptions I propagate up until they are cached and handled with some generic error handling code. When I find a checked exception that I don't really want to handle at a specific level, or that I consider a programming logic error, then I wrap it into a RuntimeException and let it bubble up. Never, ever swallow an exception without a good reason (and good reasons for doing this are rather scarce)

When I work with the codebase that does not have checked exceptions, it makes it to me a little bit harder to know before hand what can I expect when calling the function, which can break some stuff terribly.

This is all of course a matter of preference and developer skill. Both ways of programming and error handling can be equally effective (or noneffective), so I wouldn't say that there is The One Way.

All in all, I find it easier to work with Checked Exceptions, specially in large projects with lot of developers.


I think that this is an excellent question and not at all argumentative. I think that 3rd party libraries should (in general) throw unchecked exceptions. This means that you can isolate your dependencies on the library (ie you don't have to either re-throw their exceptions or throw Exception - usually bad practice). Spring's DAO layer is an excellent example of this.

On the other hand, exceptions from the core Java API should in general be checked if they could ever be handled. Take FileNotFoundException or (my favourite) InterruptedException . These conditions should almost always be handled specifically (ie your reaction to an InterruptedException is not the same as your reaction to an IllegalArgumentException ). The fact that your exceptions are checked forces developers to think about whether a condition is handle-able or not. (That said, I've rarely seen InterruptedException handled properly!)

One more thing - a RuntimeException is not always "where a developer got something wrong". An illegal argument exception is thrown when you try and create an enum using valueOf and there's no enum of that name. This is not necessarily a mistake by the developer!


Indeed, checked exceptions on the one hand increase robustness and correctness of your program (you're forced to make correct declarations of your interfaces -the exceptions a method throws are basically a special return type). On the other hand you face the problem that, since exceptions "bubble up", very often you need to change a whole lot of methods (all the callers, and the callers of the callers, and so on) when you change the exceptions one method throws.

Checked exceptions in Java do not solve the latter problem; C# and VB.NET throw out the baby with the bathwater.

A nice approach that takes the middle road is described in this OOPSLA 2005 paper (or the related technical report .)

In short, it allows you to say: method g(x) throws like f(x) , which means that g throws all the exceptions f throws. Voila, checked exceptions without the cascading changes problem.

Although it is an academic paper, I'd encourage you to read (parts of) it, as it does a good job of explaining what the benefits and downsides of checked exceptions are.


Ok... Checked exceptions are not ideal and have some caveat but they do serve a purpose. When creating an API there are specific cases of failures that are contractual of this API. When in the context of a strongly statically typed language such as Java if one does not use checked exceptions then one must rely on ad-hoc documentation and convention to convey the possibility of error. Doing so removes all benefit that the compiler can bring in handling error and you are left completely to the good will of programmers.

So, one removes Checked exception, such as was done in C#, how then can one programmatically and structurally convey the possibility of error ? How to inform the client code that such and such errors can occur and must be dealt with ?

I hear all sorts of horrors when dealing with checked exceptions, they are misused this is certain but so are unchecked exceptions. I say wait a few years when APIs are stacked many layers deep and you will be begging for the return of some kind of structured mean to convey failures.

Take the case when the exception was thrown somewhere at the bottom of the API layers and just bubbled up because nobody knew it was even possible for this error to occur, this even though it was a type of error that was very plausible when the calling code threw it (FileNotFoundException for example as opposed to VogonsTrashingEarthExcept... in which case it would not matter if we handle it or not since there is nothing left to handle it with).

Many have argued that not being able to load the file was almost always the end of the world for the process and it must die a horrible and painful death. So yeah.. sure ... ok.. you build an API for something and it loads file at some point... I as the user of said API can only respond... "Who the hell are you to decide when my program should crash !" Sure Given the choice where exceptions are gobbled up and leave no trace or the EletroFlabbingChunkFluxManifoldChuggingException with a stack trace deeper than the Marianna trench I would take the latter without a cinch of hesitation, but does this mean that it is the desirable way to deal with exception ? Can we not be somewhere in the middle, where the exception would be recast and wrapped each time it traversed into a new level of abstraction so that it actually means something ?

Lastly, most of the argument I see is "I don't want to deal with exceptions, many people do not want to deal with exceptions. Checked exceptions force me to deal with them thus I hate checked exception" To eliminate such mechanism altogether and relegate it to the chasm of goto hell is just silly and lacks jugement and vision.

If we eliminate checked exception we could also eliminate the return type for functions and always return a "anytype" variable... That would make life so much simpler now would it not ?


One important thing nobody mentioned is how it interferes with interfaces and lambda expressions.

Let's say you define a MyAppException extends Exception . It is the top level exception inherited by all exceptions thrown by your application. Every method declares throws MyAppException which is a bit of nuissance, but manageable. An exception handler logs exception and notifies the user somehow.

All looks OK until you want to implement some interface that is not yours. Obviously it doesn't declare intention to throw MyApException , so compiler doesn't allow you to throw the exception from there.

However, if your exception extends RuntimeException , there will be no problem with interfaces. You can voluntarily mention the exception in JavaDoc if you wish. But other than that it just silently bubbless through anything, to be caught in your exception handling layer.


The good proves that Checked Exception are not needed are:

  1. A lot of framework that does some work for Java. Like Spring that wraps JDBC exception to unchecked exceptions, throwing messages to the log
  2. Lot of languages that came after java, even on top on java platform - they do not use them
  3. Checked exceptions, it is kind prediction about how the client would use the code that throws an exception. But a developer who writes this code would never know about the system and business that client of code is working in. As an example Interfcace methods that force to throw checked exception. There are 100 implementation over the system, 50 or even 90 of implementations do not throw this exception, but the client still must to catch this exception if he user reference to that interface. Those 50 or 90 implementations tend to handle those exceptions inside themself, putting exception to the log (and this is good behavior for them). What we should do with that? I would better have some background logic that would do all that job - sending message to the log. And If I, as a client of code, would feel I need handle the exception - I will do it. I may forget about it, right - but if I use TDD, all my steps are covered and I know what I want.
  4. Another example when I'm working with I/O in java, it forces me to check all exception, if file does not exists? what I should do with that? If it does not exists, the system would not go to the next step. The client of this method, would not get expected content from that file - he can handle Runtime Exception, otherwise I should first check Checked Exception, put a message to log, then throw exception up out form the method. No...no - I would better do it automatically with RuntimeEception, that does it / lits up automatically. There is no any sense to handle it manually - I would be happy I saw an error message in the log (AOP can help with that.. something that fixes java). If, eventually, I deice that system should shows pop-up message to the end user - I will show it, not a problem.

I was happy if java would provide me with a choice what to use, when working with core libs, like I/O. Like provides two copies of same classes - one wrapped with RuntimeEception. Then we can compare what people would use . For now, though, many people would better go for some framework on top on java, or different language. Like Scala, JRuby whatever. Many just believe that SUN was right.


The programmer needs to know all of the exceptions that a method may throw, in order to use it correctly. So, beating him over the head with just some of the exceptions does not necessarily help a careless programmer avoid errors.

The slim benefit is outweighed by the burdensome cost (especially in larger, less flexible code bases where constantly modifying the interface signatures is not practical).

Static analysis can be nice, but truly reliable static analysis often inflexibly demands strict work from the programmer. There is a cost-benefit calculation, and the bar needs to be set high for a check that leads to a compile time error. It would be more helpful if the IDE took on the role of communicating which exceptions a method may throw (including which are unavoidable). Although perhaps it would not be as reliable without forced exception declarations, most exceptions would still be declared in documentation, and the reliability of an IDE warning is not so crucial.


To attempt to address just the unanswered question:

If you throw RuntimeException subclasses instead of Exception subclasses then how do you know what you are supposed to catch?

The question contains specious reasoning IMHO. Just because the API tells you what it throws doesn't mean you deal with it in the same way in all cases. To put it another way, the exceptions you need to catch vary depending on the context in which you use the component throwing the exception.

उदाहरण के लिए:

If I'm writing a connection tester for a database, or something to check the validity of a user entered XPath, then I'd probably want to catch and report on all checked and unchecked exceptions that are thrown by the operation.

If, however, I am writing a processing engine, I will likely treat an XPathException (checked) in the same way as an NPE: I would let it run up to the top of the worker thread, skip the rest of that batch, log the issue (or send it to a support department for diagnosis) and leave feedback for the user to contact support.


We've seen some references to C#'s chief architect.

Here's an alternate point of view from a Java guy about when to use checked exceptions. He acknowledges many of the negatives others have mentioned: Effective Exceptions







checked-exceptions