it-swarm.com.de

Welche Ausnahme für ungültige Eingaben ausgelöst werden soll, die aus Client-Sicht gültig sind

Ich schreibe Code, um 2 Linien zu finden und zu schneiden. Wenn die Steigungen der Linien gleich sind, schneiden sie sich nicht. Andererseits ist eine Eingabe mit gleichwertigen Steigungen völlig gültig.

public static Point calculateIntersection(Line line1, Line line2) {

    if (line1 == null || line2 == null) {
        throw new NullPointerException(" some message ");
    }

    if (line1.getConstant() == line2.getConstant()) {
        return new Point(0, line1.getConstant());
    }

    if (line1.getSlope() == line2.getSlope()) {
        throw new IllegalArgumentException("slopes are same, the lines do not intersect.");
    }

    int x = (line2.getConstant() - line1.getConstant()) / (line1.getSlope() - line2.getSlope());
    int y = line1.getSlope() * x + line1.getConstant();

    return new Point(x, y);
}

Die Frage ist, ob illegale Ausnahmestreitigkeiten das Richtige sind? Da die Eingabe gültig ist, überzeugt sie mich nicht vollständig.

Ist eine benutzerdefinierte Ausnahme das Richtige? Klingt nach einer guten Wahl, aber eine zusätzliche Meinung würde helfen.

Vielen Dank

32
JavaDeveloper

Die Frage ist ist das Werfen von Ausnahmen für illegale Argumente das Richtige?

Es hängt davon ab, wie Sie diesen Zustand "einrahmen" möchten/müssen. ist es ein Fehler, ein Benutzereingabefehler oder etwas, mit dem das Programm umgehen kann?

  • Wenn der Fall, dass sich zwei Linien nicht schneiden, eindeutig ein "Fehler" ist, ist IllegalArgumentException in Ordnung. Hierfür ist die Ausnahme vorgesehen. (Beachten Sie, dass es sich um eine nicht aktivierte Ausnahme handelt. Daher wird erwartet, dass sie nicht abgefangen/wiederhergestellt wird.)

  • Wenn Sie davon ausgehen, dass sich das Programm von selbst wiederherstellen kann, ist eine benutzerdefinierte Ausnahme die beste Idee. Auf diese Weise verringern Sie die Möglichkeit, dass Ihr Code durch eine Bibliotheksmethode verwirrt wird, die ein IllegalArgumentException auslöst (sagen wir) ... als etwas anderes als "zwei gekreuzte Linien".

  • Wenn Sie erwarten, dass dieser Fall dem Endbenutzer als Teil der Eingabevalidierung gemeldet wird, ist eine generische Ausnahme vom Typ "Validierungsfehler" möglicherweise angemessener als eine bestimmte benutzerdefinierte Ausnahme. Diese Methode sieht jedoch nicht so aus, als ob sie (ausschließlich) zur Überprüfung von Benutzereingaben verwendet werden soll.

35
Stephen C

Dies sollte mit ziemlicher Sicherheit keine Ausnahme auslösen, da es durchaus sinnvoll ist, eine solche Methode mit zwei beliebigen Line Werten aufzurufen. Sie haben bereits Nullwerte entsprechend behandelt.

Sie haben das Verhalten Ihrer Klasse auch in einer der schlecht definierten Eingabesituationen definiert, nämlich in zwei zusammenfallenden "konstanten" (horizontalen) Linien, in denen Sie den Punkt bei x=0 Auf dieser Linie zurückgeben. Auf ähnliche Weise sollten Sie Rückgabewerte für die anderen Fälle von schlecht definierten Eingaben auswählen: übereinstimmende vertikale Linien, übereinstimmende Linien, die weder horizontal noch vertikal sind, und nicht übereinstimmende parallele Linien.

Meiner Meinung nach wäre das natürlichste Ergebnis für den letzten Fall - nicht übereinstimmende parallele Linien - null, was die Tatsache widerspiegelt, dass es keinen Schnittpunkt gibt.

Es wäre dann Sache des Kunden, zu entscheiden, ob eine Nullkreuzung eine Ausnahme, eine Fehlermeldung oder was auch immer rechtfertigt. Z.B. Eine interaktive Shell, die den Benutzer auffordert, Linien zu schneiden, gibt möglicherweise eine Fehlermeldung aus und fordert den Benutzer auf, es erneut zu versuchen. Eine etwas kompliziertere Berechnung, z. Ein linearer Optimierer, der versucht, Grenzen für seine Suche zu definieren, möchte möglicherweise IllegalArgumentException auslösen, wenn die Einschränkungen, die zu den parallelen Linien führen, einander widersprechen.

Natürlich sollten die Rückgabewerte in all diesen Fällen (zusammenfallende Linien oder nicht zusammenfallende parallele Linien) im Javadoc der Methode genau dokumentiert werden.

4
Andy Lowry

Ich würde sagen, Sie tun das Richtige: Sie erkennen den Zustand frühzeitig. Entweder das oder die Leute beschweren sich, dass "Ihr Programm fehlerhaft ist, sehen Sie sich diese Eingabedaten an, dividiert durch 0".

Da in mehr als 99% der Situationen kein solcher Fehler auftritt, ist dies eine Ausnahmebedingung und berechtigt nicht dazu, eine aktivierte Ausnahme zu deklarieren. Eine nicht aktivierte Ausnahme ist also in der Tat die richtige Wahl.

Nun, ob IllegalArgumentException das "Gute" ist, es ist zumindest die engste Ausnahme, die diesen Fall beschreibt ... Sie können, wenn Sie das Gefühl haben, einen besseren Namen zu haben, immer Ihren eigenen erben RuntimeException.

WENN andererseits ist diese Situation nicht so selten, dann sollte möglicherweise die Logik zum Erreichen dieser Funktion überprüft werden, um diese Bedingung niemals zu erfüllen den ersten Platz.

2
fge
1
arcadeblast77

Wie @ Andy-Lowry und @ KamikazeCZ sagen, sollte dies keine Ausnahme sein.

Diese Methode sollte sich nicht damit befassen, ob der Client erwartet, dass sich Linien immer schneiden oder nicht; es sollte sich nur darum kümmern, den Schnittpunkt zweier Linien zu finden - etwas, das von Natur aus nicht passieren könnte.

Wenn der Aufrufer ein Ergebnis zurückerhält, das anzeigt, dass keine Überschneidung vorliegt, kann DIESER Code entscheiden, ob es sich um eine ungültige Eingabe handelt, weil der Endbenutzer ordnungsgemäß gewarnt wurde, oder um etwas, das er behandeln kann (möglicherweise durch erneute Aufforderung), oder eine benutzerdefinierte Ausnahme auslösen.

Also, zurück zu was sollte diese Methode zurückgeben? Eine Art Sentinel-Wert, genauso wie indexOf -1 in der Auflistungsbibliothek zurückgibt. Die Rückgabe von null ist ein vernünftiger Sentinel. In Java 8 können Sie einen Optional<Point> Zurückgeben, um den Aufrufer daran zu erinnern, dass es möglicherweise keinen richtigen Point gibt.

Sie haben noch ein weiteres Problem: Was fragt jemand nach dem Schnittpunkt einer Linie mit sich selbst? (Mathematisch gesehen ist der Schnittpunkt zweier Linien entweder 0 Punkte, 1 Punkt oder unendlich viele Punkte.) Möglicherweise müssen Sie in Java zwei Sentinel-Werte zurückgeben können, was in Java eine größere Rolle spielt. Diese Methode könnte sich dieses Mal von der Situation lösen, indem sie sagt: "Bei mehreren Antworten kann diese Methode eine von ihnen zurückgeben", oder (was ich wahrscheinlich tun würde) "... gibt den Punkt zurück, der dem Ursprung am nächsten liegt". .

Übrigens folgt dieses Denken größtenteils aus einem Unit-Test-Denken: Beginnen Sie damit, die richtige Antwort für eine Vielzahl von Eckdaten zu definieren, bevor Sie mit dem Code beginnen und sich auf einen bestimmten Rückgabetyp festlegen usw.

Schließlich: Achten Sie beim Vergleich der Ergebnisse von getSlope() mit == Auf Gleitkomma-Rundungsfehler. Es ist vielleicht das Beste, was man hier machen kann, aber es ist immer noch problematisch. Die Art und Weise, wie Sie den Schnittpunkt mit ints annehmen (oder abrunden), deutet jedoch darauf hin, dass Ihr Problem möglicherweise sehr spezielle Einschränkungen/Annahmen enthält.

1
not-just-yeti