Wie gehe ich mit geprüften Ausnahmen um, die niemals ausgelöst werden können?


35

Beispiel:

foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");

Da die Codierung fest codiert und korrekt ist, wird der Konstruktor niemals die in der Spezifikation deklarierte UnsupportedEncodingException auslösen (es sei denn, die Java-Implementierung ist fehlerhaft, in diesem Fall bin ich trotzdem verloren). Java zwingt mich sowieso, mit dieser Ausnahme umzugehen.

Derzeit sieht es so aus

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
}
catch(UnsupportedEncodingException e) { /* won't ever happen */ }

Irgendwelche Ideen, wie man es besser macht?


4
Schreiben Sie für eine echte Herausforderung einen Komponententest, um sicherzustellen, dass dieser Fang tatsächlich funktioniert.
Jay Elston

1
`throw new ImpossibleException (" Das Universum neu starten. Die Dinge sind durcheinander ", e);
Chris Cudmore

1
"Wird nie passieren" wird ...

Thorbjørn Ravn Andersen: Möglicherweise wird nach dem Ändern des Programms, aber zumindest im aktuellen Zustand, kein Satz von Eingabedaten die Ausnahme auslösen können.
user281377

In Ihrem Beispiel oben wird eine Ausnahme ausgelöst, da die Methode nicht weiß, ob sie mit einer unterstützten oder nicht unterstützten Codierung aufgerufen wird. Ein Ausweg wäre, wenn es einen anderen Konstruktor gäbe, der davon ausgeht, dass ein Standardzeichensatz angegeben wurde, der nicht deklarieren müsste, dass eine Ausnahme ausgelöst wird.
Jordanien

Antworten:


27

Ich habe die Gewohnheit, nur um auf der sicheren Seite zu sein, einen assertin den Fangblock zu stecken. Jemand könnte den Inhalt des tryBlocks später ändern , und Sie möchten wissen, ob der Code fehlschlägt, oder nicht?


Gute Idee; ein einfaches assert false;fügt nicht zu viel Unordnung hinzu und macht klar, dass ich davon ausgehe, dass der catch-Block niemals betreten wird.
user281377

5
@ammoQ, oder Sie können auch eine Nachricht hinzufügen, um Ihre Absicht absolut klar: assert false : "should never happen".
Péter Török,

13
Noch besser: "Sollte niemals passieren, da Java die Unterstützung des Zeichensatzes ISO-8859-1 erfordert."
Dan04

3
assertimpliziert, dass Assertions aktiviert sind. Ich werfe ein UnexpectedException(was auch den Vorteil hat, dass ich einen Stack Trace habe ...).
Chop

35

Wenn ich einen Cent für jedes Mal bekommen hätte, wenn ich ein Protokoll / einen Fehler "Das sollte niemals passieren" gesehen hätte, hätte ich ... nun, zwei Cent. Aber dennoch...

Leere Fangklötze lassen meine Spinnengefühle kribbeln und die meisten guten Code-Analysetools beklagen sich. Ich würde um jeden Preis vermeiden, sie leer zu lassen. Sicher, jetzt wissen Sie, dass der Fehler niemals auftreten kann, aber in einem Jahr führt jemand ein globales Suchen-Ersetzen von "ISO-8859-1" durch, und plötzlich kann es sein, dass Sie einen äußerst schwer zu findenden Fehler haben.

Der assert falseVorschlag ist gut, aber da Zusicherungen zur Laufzeit deaktiviert werden können, sind sie keine Garantie. Ich würde RuntimeExceptionstattdessen eine verwenden. Diese müssen nicht von aufrufenden Klassen abgefangen werden, und wenn sie jemals auftreten, wird ein Stack-Trace erstellt, der vollständige Informationen liefert.


28

Ich habe es immer so gemacht:

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
} catch(UnsupportedEncodingException e) {
    throw new AssertionError(e);
}

Mag etwas ausführlich sein (Java ist ...), aber zumindest wird ein Assertionsfehler angezeigt, wenn das Unmögliche möglich ist.

Wenn die Java-Implementierung fehlerhaft ist, sollten Sie so schnell wie möglich eine möglichst gute Fehlermeldung erhalten, anstatt nur das Unmögliche zu ignorieren. Und selbst wenn die Java-Implementierung nicht kaputt ist, könnte jemand Ihren Code in geändert haben "UTF8"(hoppla - sollte es gewesen sein "UTF-8"?).

Dies sollte in erster Linie eine Laufzeitausnahme gewesen sein. JDK steckt voller falscher Entscheidungen.


4
Die wirklich schlechte Entscheidung (oder Auslassung, wenn Sie möchten) ist, dass es keine vordefinierten Charset-Instanzen für die 6 von Java benötigten Zeichensätze gibt. foobar = new InputStreamReader(p.getInputStream(), Charset.ISO_8859_1);- Wäre das nicht schöner und würde man nicht ein für alle Mal einen Fehler machen?
user281377

3
Die Guava-Bibliothek hat Tonnen von diesen Dingen. Erleichtert das Leben.

3
In Java 1.7+ sind Zeichensatzkonstanten definiert: docs.oracle.com/javase/7/docs/api/java/nio/charset/… . Verwenden Sie sie wie folgt: StandardCharsets.UTF_8.displayName ()
Michael

4

Wenn Sie der einzige Entwickler sind, der diesen Code jemals sehen wird, würde ich sagen, dass es in Ordnung ist. Wenn Sie dies nicht tun, würde ich dies als echte Möglichkeit betrachten oder zumindest den Kommentar "Wird nie passieren" ändern etwas nützlicheres.


4

Der Teil dieser Ausnahmen, der mich am meisten stört, ist, dass es meine Codeabdeckung verletzt.

Wenn ich in Bezug auf die Berichterstattung zwanghaft werde, rolle ich das Try / Catch auf, das "niemals passieren kann" (... oder nur, wenn ich eine mutierte JVM verwende, die irgendwie vergessen hat, "US-ASCII" aufzunehmen) Eine Klasse und Methode, die diesen Versuch / Fang kapselt und die aktivierte Ausnahme auf eine der hier genannten Arten ersetzt (normalerweise wird eine nicht aktivierte Ausnahme durch eine Snide-Nachricht ausgelöst).

Dann hat meine Codeabdeckung einen Treffer in der Utility-Klasse, aber nicht in allen Verweisen auf diese Operation, die über meinen Code verstreut sind.

Manchmal nehme ich mir die Zeit, um wie Operationen in einer Klasse mit tatsächlich kohärenter Semantik aufzurollen. Aber da es für meine Teamkollegen ziemlich offensichtlich ist, was los ist, halte ich es normalerweise so einfach wie möglich und mache mir nicht so viele Gedanken über das bestmögliche Design.

Wie bereits erwähnt, haben Guava und andere Bibliotheken Möglichkeiten, diesen Schmerz zu lindern - aber das ist im Grunde die gleiche Strategie. Bewegen Sie den Ärger von der Bühne, damit Ihr Hauptcode den Treffer in der Berichterstattung nicht mitmacht.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.