2013-03-04 18 views
67

Ich bin besorgt, dass dies eine Laufzeitausnahme ist, so dass es wahrscheinlich sparsam verwendet werden sollte.
Standard-Anwendungsfall:Wann sollte eine IllegalArgumentException ausgelöst werden?

void setPercentage(int pct) { 
    if(pct < 0 || pct > 100) { 
     throw new IllegalArgumentException("bad percent"); 
    } 
} 

Aber das scheint, wie es die folgende Konstruktion zwingen würde:

es
public void computeScore() throws MyPackageException { 
     try { 
      setPercentage(userInputPercent); 
     } 
     catch(IllegalArgumentException exc){ 
      throw new MyPackageException(exc); 
     } 
} 

Um wieder eine geprüfte Ausnahme zu sein.

Okay, aber lass uns damit gehen. Wenn Sie eine schlechte Eingabe geben, erhalten Sie einen Laufzeitfehler. Also erstens, das ist eigentlich eine ziemlich schwierige Politik einheitlich zu implementieren, da Sie das Gegenteil Umwandlung zu tun haben könnten:

public void scanEmail(String emailStr, InputStream mime) { 
    try { 
     EmailAddress parsedAddress = EmailUtil.parse(emailStr); 
    } 
    catch(ParseException exc){ 
     throw new IllegalArgumentException("bad email", exc); 
    } 
} 

Und schlimmer noch - während 0 <= pct && pct <= 100 der Client-Code Überprüfung zu erwarten ist statisch zu tun, ist dies nicht so Für komplexere Daten wie eine E-Mail-Adresse oder noch schlimmer, etwas, das mit einer Datenbank verglichen werden muss. Daher kann der Client-Code im Allgemeinen nicht vorab validiert werden.

Also im Grunde, was ich sage ist, sehe ich keine sinnvolle konsistente Politik für die Verwendung von IllegalArgumentException. Es scheint, dass es nicht verwendet werden sollte und wir sollten bei unseren eigenen geprüften Ausnahmen bleiben. Was ist ein guter Anwendungsfall, um dies zu werfen?

Antwort

51

Die api doc für Illegal ist:

Geworfen, um anzuzeigen, dass ein Verfahren zur Herstellung eines Unerlaubten Argument übergeben wurde.

Aus bei how it is used in the jdk libraries suchen, würde ich sagen:

  • Es ist wie eine defensive Maßnahme scheint zu offensichtlich schlecht Eingang zu beschweren, bevor der Eingang in die Werke erhalten und etwas bewirken auf halber Strecke zum Scheitern verurteilt durch mit einer unsinnigen Fehlermeldung.

  • Es wird für Fälle verwendet, in denen es zu lästig wäre, eine geprüfte Ausnahme zu werfen (obwohl es im java.lang.reflect-Code erscheint, wo Bedenken über lächerliche Ebenen von checked-exception-throwing nicht offensichtlich sind).

ich Illegal verwenden würde allerletzten defensive Argument-Überprüfung für gemeinsamen Dienstprogramme zu tun (versuchen, mit der jdk Nutzung konsistent zu bleiben), wo die Erwartung ist, dass ein schlechtes Argument ein Programmierer Fehler, ähnlich wie ein ist NPE. Ich würde es nicht verwenden, um die Validierung im Geschäftscode zu implementieren. Ich würde es sicherlich nicht für das E-Mail-Beispiel verwenden.

+5

Ich denke, der Ratschlag "wo die Erwartung ist, dass ein schlechtes Argument ein Programmiererfehler ist" ist am besten mit dem überein, wie ich das verwendet habe, also akzeptiere diese Antwort. – djechlin

9

Laufzeitausnahmen "sparsam" zu werfen ist nicht wirklich eine gute Richtlinie - Effektives Java empfiehlt, dass Sie überprüfte Ausnahmen verwenden, wenn vernünftigerweise erwartet werden kann, dass der Aufrufer wiederherstellt. (Programmierfehler ist ein spezifisches Beispiel: Wenn ein bestimmter Fall einen Programmiererfehler anzeigt, dann sollten Sie eine ungeprüfte Ausnahme auslösen; Sie möchten, dass der Programmierer einen Stack-Trace darüber hat, wo das logische Problem aufgetreten ist. Versuchen Sie nicht, ihn selbst zu behandeln.)

Wenn es keine Hoffnung auf Wiederherstellung gibt, dann können Sie auch ungeprüfte Ausnahmen verwenden. es hat keinen Sinn, sie zu fangen, also ist das völlig in Ordnung.

Es ist nicht 100% klar von Ihrem Beispiel welcher Fall dieses Beispiel in Ihrem Code ist.

+0

Ich denke "vernünftigerweise zu erholen" ist Wiesel. Jede Operation 'foo (data)' könnte als Teil von 'for (Daten data: list) foo (data);' geschehen, in der der Aufrufer so viele wie möglich erfolgreich ausführen möchte, obwohl einige Daten fehlerhaft sind.Beinhaltet auch programmatische Fehler, wenn meine Anwendung ausfällt, bedeutet das, dass eine Transaktion nicht durchgeführt wird. Das ist wahrscheinlich besser. Wenn das bedeutet, dass die Kernkühlung offline geht, ist das schlecht. – djechlin

+0

'StackOverflowError' und solche Fälle, von denen der Aufrufer vernünftigerweise nicht erwarten kann, dass er von ihnen wiederherstellt. Aber es klingt wie jeder Fall von Daten oder Anwendungslogikebene überprüft werden sollte. Das bedeutet, dass Ihr Nullzeiger prüft! – djechlin

+3

In einer Kernkühlung-Anwendung würde ich lieber hart in Tests ausfallen, als einen Fall zuzulassen, den der Programmierer für unbemerkt halten konnte. –

4

Wie in oracle offiziellen Tutorial angegeben, heißt es, dass:

Wenn ein Client von einer Ausnahme werden kann vernünftigerweise erwartet erholen, macht es eine geprüfte Ausnahme. Wenn ein Client nichts tun kann, um von der Ausnahme wiederherzustellen, machen Sie eine unchecked Ausnahme.

Wenn ich eine Anwendung mit Datenbank interagieren JDBC mit, Und ich habe eine Methode, die das Argument als int item und double price nimmt. Die price für das entsprechende Element wird aus der Datenbanktabelle gelesen. Ich multipliziere einfach die Gesamtanzahl von item gekauft mit dem price Wert und gebe das Ergebnis zurück. Obwohl ich immer an meinem Ende sicher bin (Anwendungsende), dass Preisfeldwert in der Tabelle niemals negativ sein könnte. Aber was ist, wenn der Preiswert herauskommt negativ? Es zeigt, dass es ein ernstes Problem mit der Datenbankseite gibt. Vielleicht falsche Preiseingabe durch den Betreiber. Dies ist die Art von Problem, das der andere Teil der Anwendung, der diese Methode aufruft, nicht antizipieren kann und sich nicht davon erholen kann. Es ist ein BUG in Ihrer Datenbank.So, und IllegalArguementException() sollte in diesem Fall geworfen werden, die the price can't be negative würde angeben.
Ich hoffe, dass ich meinen Standpunkt klar zum Ausdruck gebracht haben ..

17

Wenn Sie von "schlechter Eingabe" sprechen, sollten Sie überlegen, woher die Eingabe kommt.

Wenn die Eingabe von einem Benutzer oder einem anderen externen System eingegeben wurde, das Sie nicht steuern, sollten Sie erwarten, dass die Eingabe ungültig ist, und sie immer bestätigen. Es ist vollkommen in Ordnung, eine geprüfte Ausnahme in diesem Fall zu werfen. Ihre Anwendung sollte diese Ausnahme "wiederherstellen", indem sie eine Fehlermeldung an den Benutzer sendet.

Wenn die Eingabe von Ihrem eigenen System stammt, z. Ihre Datenbank oder einige andere Teile Ihrer Anwendung sollten Sie sich darauf verlassen können, dass sie gültig ist (sie sollte validiert worden sein, bevor sie dort angekommen ist). In diesem Fall ist es völlig in Ordnung, eine ungeprüfte Ausnahme wie eine IllegalArgumentException auszulösen, die nicht abgefangen werden sollte (im Allgemeinen sollten Sie keine ungeprüften Ausnahmen abfangen). Es ist ein Programmierfehler, dass der ungültige Wert an erster Stelle angekommen ist;) Sie müssen es beheben.

+1

Warum "sollten Sie nie ungeprüfte Ausnahmen fangen"? –

+5

Weil eine ungeprüfte Ausnahme als Ergebnis eines Programmierfehlers ausgelöst werden soll. Es kann nicht vernünftigerweise erwartet werden, dass der Aufrufer einer Methode, die solche Ausnahmen auslöst, sich davon erholen kann, und daher macht es normalerweise keinen Sinn, sie abzufangen. – Tom

+0

'Weil eine ungeprüfte Ausnahme als Ergebnis eines Programmierfehlers ausgelöst werden soll 'half mir eine Menge Dinge in meinem Kopf zu löschen, danke :) – svarog

5

sollte Jede API überprüft die Gültigkeit der einzelnen Parameter eines öffentlichen Verfahrens vor der Ausführung:

void setPercentage(int pct, AnObject object) { 
    if(pct < 0 || pct > 100) { 
     throw new IllegalArgumentException("pct has an invalid value"); 
    } 
    if (object == null) { 
     throw new IllegalArgumentException("object is null"); 
    } 
} 

Sie 99,9% der Zeit Fehler bei der Anwendung dar, weil es für unmöglich Operationen zu fragen ist so in dem Ende sie sind Fehler, die die Anwendung zum Absturz bringen sollten (es ist also ein nicht behebbarer Fehler).

In diesem Fall und nach dem Ansatz von fail fast sollten Sie die Anwendung beenden lassen, um eine Beschädigung des Anwendungsstatus zu vermeiden.

+0

Im Gegensatz dazu, wenn ein API-Client mir einen schlechten Input gibt, ich sollte * nicht * meinen gesamten API-Server zum Absturz bringen. – djechlin

+0

Natürlich sollte es Ihren API-Server nicht zum Absturz bringen, sondern eine Ausnahme an den Aufrufer zurückgeben, die nichts außer dem Client zum Absturz bringen sollte. –

+0

Was Sie im Kommentar geschrieben haben, ist nicht das, was Sie in der Antwort geschrieben haben. – djechlin

Verwandte Themen