[Java] Der Fall gegen geprüfte Ausnahmen


Answers

Die Sache über geprüfte Ausnahmen ist, dass sie nicht wirklich Ausnahmen durch das übliche Verständnis des Konzepts sind. Sie sind stattdessen API-alternative Rückgabewerte.

Die ganze Idee von Exceptions ist, dass ein Fehler, der irgendwo in der Call-Kette ausgelöst wird, platzen kann und von Code irgendwo weiter oben verarbeitet wird, ohne dass sich der Intervening-Code darum kümmern muss. Checked Exceptions andererseits verlangen, dass jede Ebene des Codes zwischen dem Werfer und dem Fänger erklärt, dass sie über alle Arten von Ausnahmen, die sie durchlaufen können, Bescheid wissen. Das ist in der Praxis wirklich etwas anders, wenn die geprüften Ausnahmen einfach spezielle Rückgabewerte sind, nach denen der Aufrufer suchen muss. zB [Pseudocode]:

public [int or IOException] writeToStream(OutputStream stream) {
    [void or IOException] a= stream.write(mybytes);
    if (a instanceof IOException)
        return a;
    return mybytes.length;
}

Da Java keine alternativen Rückgabewerte oder einfache Inline-Tupel als Rückgabewerte verwenden kann, sind geprüfte Ausnahmen eine sinnvolle Antwort.

Das Problem ist, dass viel Code, einschließlich großer Teile der Standardbibliothek, geprüfte Ausnahmen für echte Ausnahmezustände missbraucht, die Sie sehr wahrscheinlich mehrere Ebenen erfassen möchten. Warum ist IOException keine RuntimeException? In jeder anderen Sprache kann ich eine E / A-Ausnahme passieren lassen, und wenn ich nichts unternehme, wird meine Anwendung gestoppt und ich bekomme einen praktischen Stack-Trace zum Anschauen. Das ist das Beste, was passieren kann.

Vielleicht zwei Methoden von dem Beispiel, dass Sie alle IOExceptions aus dem gesamten Schreiben-zu-Stream-Prozess abfangen möchten, brechen Sie den Prozess ab und springen Sie in den Fehlerberichtscode; In Java können Sie das nicht ohne Hinzufügen von 'throws IOException' auf jeder Aufrufebene tun, sogar auf Ebenen, die selbst keine IO haben. Solche Methoden sollten nicht über die Ausnahmebehandlung wissen müssen; müssen Ausnahmen zu ihren Signaturen hinzufügen:

  1. erhöht unnötigerweise die Kopplung;
  2. macht Interface-Signaturen sehr spröde zu verändern;
  3. macht den Code weniger lesbar;
  4. ist so ärgerlich, dass es die übliche Reaktion des Programmierers ist, das System zu besiegen, indem man etwas Schreckliches tut, wie "Exception auslösen", "catch (Exception e) {}" oder alles in eine RuntimeException einfügen (was das Debuggen schwieriger macht).

Und dann gibt es viele nur lächerliche Bibliotheksausnahmen wie:

try {
    httpconn.setRequestMethod("POST");
} catch (ProtocolException e) {
    throw new CanNeverHappenException("oh dear!");
}

Wenn Sie Ihren Code mit lächerlichem Crud wie diesem auffüllen müssen, ist es kein Wunder, dass checked Ausnahmen einen Haufen Hass erhalten, obwohl dies wirklich nur ein einfaches schlechtes API-Design ist.

Ein weiterer besonders schlechter Effekt ist die Inversion der Kontrolle, wo die Komponente A einen Rückruf an die generische Komponente B liefert. Die Komponente A möchte eine Ausnahme von ihrem Callback zurück an den Ort werfen lassen, an dem sie die Komponente B aufgerufen hat, aber nicht weil das die Callback-Schnittstelle ändern würde, die von B behoben wird. Ein kann nur tun, indem es die echte Ausnahme in eine RuntimeException einhüllt, die noch mehr Ausnahmebehandlungs-Textbausteine ​​zum Schreiben ist.

Überprüfte Ausnahmen, wie sie in Java implementiert sind, und deren Standardbibliothek bedeuten Muster, Muster, Muster. In einer bereits ausführlichen Sprache ist das kein Gewinn.

Question

Seit einigen Jahren kann ich keine vernünftige Antwort auf die folgende Frage finden: Warum sind einige Entwickler so gegen geprüfte Ausnahmen? Ich hatte zahlreiche Gespräche, las auf Blogs und las, was Bruce Eckel zu sagen hatte (die erste Person, die ich sah, sprach sich gegen sie aus).

Ich schreibe gerade einen neuen Code und achte sehr genau darauf, wie ich mit Ausnahmen umgehen kann. Ich versuche, den Standpunkt der "wir mögen keine geprüften Ausnahmen" zu sehen, und ich kann es immer noch nicht sehen.

Jedes Gespräch, das ich habe, endet mit der gleichen unbeantworteten Frage ... lass mich es einrichten:

Im Allgemeinen (wie Java entwickelt wurde),

  • Fehler ist für Dinge, die nie gefangen werden sollten (VM hat eine Erdnussallergie und jemand hat ein Glas Erdnüsse darauf fallen lassen)
  • RuntimeException ist für Dinge, die der Programmierer falsch gemacht hat (Programmierer ging vom Ende eines Arrays)
  • Ausnahme (außer RuntimeException) ist für Dinge, die außerhalb der Kontrolle des Programmierers liegen (Festplatte füllt sich beim Schreiben in das Dateisystem, Dateizugriffsgrenze für den Prozess wurde erreicht und Sie können keine weiteren Dateien öffnen)
  • Throwable ist einfach das übergeordnete Element aller Ausnahmetypen.

Ein häufiges Argument, das ich höre, ist, dass, wenn eine Ausnahme auftritt, der Entwickler das Programm beenden wird.

Ein anderes häufiges Argument, das ich höre, ist, dass überprüfte Ausnahmen es schwieriger machen, Code zu refaktorieren.

Für das Argument "alles, was ich tun werde ist" sage ich, dass selbst wenn Sie beenden, Sie eine sinnvolle Fehlermeldung anzeigen müssen. Wenn Sie nur auf Fehler bei der Handhabung stossen, werden Ihre Benutzer nicht übermäßig glücklich sein, wenn das Programm ohne eine klare Angabe des Grundes endet.

Für die "es macht es schwer, umzuformen", zeigt dies an, dass das richtige Abstraktionsniveau nicht gewählt wurde. Anstatt zu deklarieren, dass eine Methode eine IOException auslöst, sollte die IOException in eine Ausnahme umgewandelt werden, die für das, was vor sich geht, besser geeignet ist.

Ich habe kein Problem damit, Main mit catch (Exception) zu umhüllen (oder in einigen Fällen catch (Throwable), um sicherzustellen, dass das Programm ordnungsgemäß beendet werden kann - aber ich erwische immer die spezifischen Ausnahmen, die ich brauche. zeigen Sie mindestens eine entsprechende Fehlermeldung an.

Die Frage, auf die die Leute niemals antworten, ist folgende:

Wenn Sie RuntimeException-Unterklassen anstelle von Exception-Unterklassen auslösen, woher wissen Sie dann, was Sie fangen sollen?

Wenn die Antwort Catch Exception ist, haben Sie auch Programmiererfehler auf dieselbe Weise wie Systemausnahmen. Das scheint mir falsch zu sein.

Wenn Sie Throwable fangen, behandeln Sie Systemausnahmen und VM-Fehler (und dergleichen) auf die gleiche Weise. Das scheint mir falsch zu sein.

Wenn die Antwort ist, dass Sie nur die Ausnahmen fangen, von denen Sie wissen, dass sie geworfen werden, woher wissen Sie dann, welche geworfen werden? Was passiert, wenn Programmierer X eine neue Ausnahme auslöst und vergessen hat, sie zu fangen? Das erscheint mir sehr gefährlich.

Ich würde sagen, dass ein Programm, das einen Stack-Trace anzeigt, falsch ist. Mögen Leute, die geprüfte Ausnahmen nicht mögen, das nicht?

Also, wenn Sie keine geprüften Ausnahmen mögen, können Sie erklären, warum nicht UND beantworten Sie die Frage, die nicht beantwortet wird, bitte?

Edit: Ich bin nicht auf der Suche nach Rat, wann beide Modelle zu verwenden, was ich suche, ist, warum Menschen aus RuntimeException erweitern, weil sie nicht gerne von Exception und / oder warum sie eine Ausnahme abfangen und dann eine RuntimeException erneut statt Fügen Sie Würfe zu ihrer Methode hinzu. Ich möchte die Motivation verstehen, abgelöste Ausnahmen zu missachten.




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.



Nun, es geht nicht darum, einen Stacktrace anzuzeigen oder stumm zu stürzen. Es geht darum, Fehler zwischen den Schichten zu kommunizieren.

Das Problem mit geprüften Ausnahmen ist, dass sie die Leute ermutigen, wichtige Details zu verschlucken (nämlich die Ausnahmeklasse). Wenn Sie sich entscheiden, dieses Detail nicht zu verschlucken, müssen Sie weiterhin throws-Deklarationen für Ihre gesamte App hinzufügen. Das bedeutet, 1) dass ein neuer Ausnahmetyp viele Funktionssignaturen beeinflusst, und 2) Sie eine bestimmte Instanz der Ausnahme vermissen können, die Sie eigentlich fangen wollen (sagen Sie, Sie öffnen eine sekundäre Datei für eine Funktion, die Daten in eine schreibt Die sekundäre Datei ist optional, Sie können also ihre Fehler ignorieren, aber da die Signatur throws IOException , ist dies leicht zu übersehen.

Ich beschäftige mich jetzt tatsächlich mit dieser Situation in einer Anwendung. Wir haben fast Ausnahmen als AppSpecificException neu verpackt. Das machte Signaturen wirklich sauber und wir mussten uns keine Gedanken über explodierende throws in Signaturen machen.

Natürlich müssen wir jetzt die Fehlerbehandlung auf den höheren Ebenen spezialisieren, indem wir die Wiederholungslogik und dergleichen implementieren. Alles ist jedoch AppSpecificException, daher können wir nicht sagen "Wenn eine IOException ausgelöst wird, versuchen Sie es erneut" oder "Wenn ClassNotFound ausgelöst wird, brechen Sie den Vorgang vollständig ab". Wir haben keine zuverlässige Möglichkeit, die echte Ausnahme zu erreichen, da Dinge immer wieder neu verpackt werden, wenn sie zwischen unserem Code und dem Code von Drittanbietern ausgetauscht werden.

Deshalb bin ich ein großer Fan der Ausnahmebehandlung in Python. Sie können nur die Dinge fangen, die Sie wollen und / oder handhaben können. Alles andere sprudelt auf, als ob du es selbst wieder aufträgst (was du sowieso getan hast).

Ich habe immer wieder festgestellt, und während des gesamten Projekts, das ich erwähnte, fällt die Ausnahmebehandlung in 3 Kategorien:

  1. Fangen und behandeln Sie eine bestimmte Ausnahme. Dies dient zum Beispiel zur Implementierung einer Wiederholungslogik.
  2. Andere Ausnahmen abfangen und erneut ausführen Alles, was hier passiert, ist normalerweise Logging, und es ist normalerweise eine triste Nachricht wie "Kann $ filename nicht öffnen". Das sind Fehler, über die man nichts machen kann; nur ein höheres Niveau weiß genug, um damit umzugehen.
  3. Fange alles und zeige eine Fehlermeldung an. Dies liegt normalerweise an der Wurzel eines Dispatcher und stellt lediglich sicher, dass der Fehler dem Aufrufer über einen Nicht-Exception-Mechanismus (Popup-Dialog, Marshalling eines RPC-Fehlerobjekts usw.) mitgeteilt werden kann.



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.




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




My writeup on c2.com is still mostly unchanged from its original form: CheckedExceptionsAreIncompatibleWithVisitorPattern

In summary:

Visitor Pattern and its relatives are a class of interfaces where the indirect caller and interface implementation both know about an exception but the interface and direct caller form a library that cannot know.

The fundamental assumption of CheckedExceptions is all declared exceptions can be thrown from any point that calls a method with that declaration. The VisitorPattern reveals this assumption to be faulty.

The final result of checked exceptions in cases like these is a lot of otherwise useless code that essentially removes the compiler's checked exception constraint at runtime.

As for the underlying problem:

My general idea is the top-level handler needs to interpret the exception and display an appropriate error message. I almost always see either IO exceptions, communication exceptions (for some reason APIs distinguish), or task-fatal errors (program bugs or severe problem on backing server), so this should not be too hard if we allow a stack trace for a severe server problem.




Zusamenfassend:

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.




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.

Beispielsweise:

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.




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.




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. Zeitraum. 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.

Fazit

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.




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.




Checked exceptions were, in their original form, an attempt to handle contingencies rather than failures. The laudable goal was to highlight specific predictable points (unable to connect, file not found, etc) & ensure developers handled these.

What was never included in the original concept, was to force a vast range of systemic & unrecoverable failures to be declared. These failures were never correct to be declared as checked exceptions.

Failures are generally possible in code, and EJB, web & Swing/AWT containers already cater for this by providing an outermost “failed request” exception-handler. The most basic correct strategy is to rollback the transaction & return an error.

One crucial point, is that runtime & checked exceptions are functionally equivalent. There is no handling or recovery which checked exceptions can do, that runtime exceptions can't.

The biggest argument against “checked” exceptions is that most exceptions can't be fixed. The simple fact is, we don't own the code/ subsystem that broke. We can't see the implementation, we're not responsible for it, and can't fix it.

If our application is not a DB.. we shouldn't try and fix the DB. That would violate the principle of encapsulation .

Particularly problematic have been the areas of JDBC (SQLException) and RMI for EJB (RemoteException). Rather than identifying fixable contingencies as per the original “checked exception” concept, these forced pervasive systemic reliability issues, not actually fixable, to be widely declared.

The other severe flaw in the Java design, was that exception-handling should correctly placed at the highest possible "business" or "request" level. The principle here is "throw early, catch late". Checked exceptions do little but get in the way of this.

We have an obvious issue in Java of requiring thousands of do-nothing try-catch blocks, with a significant proportion (40%+) being miscoded. Almost none of these implement any genuine handling or reliability, but impose major coding overhead.

Lastly, "checked exceptions" are pretty much incompatible with FP functional programming.

Their insistence on "handle immediately" is at odds with both "catch late" exception-handling best practice, and any FP structure which abstracts loops/ or flow of control.

Many people talk about "handling" checked exceptions, but are talking through their hats. Continuing after a failure with null, incomplete or incorrect data to pretend success is not handling anything. It's engineering/ reliability malpractice of the lowest form.

Failing cleanly, is the most basic correct strategy for handling an exception. Rolling back the transaction, logging the error & reporting a "failure" response to the user are sound practice -- and most importantly, prevent incorrect business data being committed to the database.

Other strategies for exception-handling are "retry", "reconnect" or "skip", at the business, subsystem, or request level. All of these are general reliability strategies, and work well/ better with runtime exceptions.

Lastly, it is far preferable to fail, than to run with incorrect data. Continuing will either cause secondary errors, distant from the original cause & harder to debug; or will eventually result in erroneous data being committed. People get fired for that.

Sehen:
- literatejava.com/exceptions/…




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.




SNR

Firstly, checked exceptions decrease the "signal-to-noise ratio" for the code. Anders Hejlsberg also talks about imperative vs declarative programming which is a similar concept. Anyway consider the following code snippets:

Update UI from non UI-thread in Java:

try {  
    // Run the update code on the Swing thread  
    SwingUtilities.invokeAndWait(() -> {  
        try {
            // Update UI value from the file system data  
            FileUtility f = new FileUtility();  
            uiComponent.setValue(f.readSomething());
        } catch (IOException e) {  
            throw new UncheckedIOException(e);
        }
    });
} catch (InterruptedException ex) {  
    throw new IllegalStateException("Interrupted updating UI", ex);  
} catch (InvocationTargetException ex) {
    throw new IllegalStateException("Invocation target exception updating UI", ex);
}

Update UI from non UI-thread in C#:

private void UpdateValue()  
{  
   // Ensure the update happens on the UI thread  
   if (InvokeRequired)  
   {  
       Invoke(new MethodInvoker(UpdateValue));  
   }  
   else  
   {  
       // Update UI value from the file system data  
       FileUtility f = new FileUtility();  
       uiComponent.Value = f.ReadSomething();  
   }  
}  

Which seems a lot clearer to me. When you start to do more and more UI work in Swing checked exceptions start to become really annoying and useless.

Jail Break

To implement even the most basic of implementations, such as Java's List interface, checked exceptions as a tool for design by contract fall down. Consider a list that is backed by a database or a filesystem or any other implementation that throws a checked exception. The only possible implementation is to catch the checked exception and rethrow it as an unchecked exception:

@Override
public void clear()  
{  
   try  
   {  
       backingImplementation.clear();  
   }  
   catch (CheckedBackingImplException ex)  
   {  
       throw new IllegalStateException("Error clearing underlying list.", ex);  
   }  
}  

And now you have to ask what is the point of all that code? The checked exceptions just add noise, the exception has been caught but not handled and design by contract (in terms of checked exceptions) has broken down.

Fazit

  • Catching exceptions is different to handling them.
  • Checked exceptions add noise to the code.
  • Exception handling works well in C# without them.

I blogged about this previously .




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.




Links