True-Way-Lösung in Java: Analysieren Sie 2 Zahlen aus 2 Zeichenfolgen und geben Sie dann deren Summe zurück


84

Eine ziemlich dumme Frage. Angesichts des Codes:

public static int sum(String a, String b) /* throws? WHAT? */ {
  int x = Integer.parseInt(a); // throws NumberFormatException
  int y = Integer.parseInt(b); // throws NumberFormatException
  return x + y;
}

Können Sie sagen, ob es sich um gutes Java handelt oder nicht? Ich spreche von NumberFormatExceptioneiner ungeprüften Ausnahme. Sie müssen es nicht als Teil der sum()Signatur angeben . Soweit ich weiß, soll die Idee von ungeprüften Ausnahmen nur signalisieren, dass die Implementierung des Programms falsch ist, und noch mehr ist es eine schlechte Idee, ungeprüfte Ausnahmen abzufangen, da es so ist , als würde man ein schlechtes Programm zur Laufzeit reparieren .

Würde jemand bitte klären, ob:

  1. Ich sollte NumberFormatExceptionals Teil der Signatur der Methode angeben .
  2. Ich sollte meine eigene geprüfte Ausnahme ( BadDataException) definieren, NumberFormatExceptioninnerhalb der Methode behandeln und sie erneut als auslösen BadDataException.
  3. Ich sollte meine eigene aktivierte Ausnahme ( BadDataException) definieren, beide Zeichenfolgen wie reguläre Ausdrücke validieren und meine auslösen, BadDataExceptionwenn sie nicht übereinstimmen.
  4. Deine Idee?

Update :

Stellen Sie sich vor, es ist kein Open-Source-Framework, das Sie aus irgendeinem Grund verwenden sollten. Sie sehen sich die Signatur der Methode an und denken: "OK, sie wirft nie". Dann hast du eines Tages eine Ausnahme. Es ist normal?

Update 2 :

Es gibt einige Kommentare, die besagen, dass mein sum(String, String)Design schlecht ist. Ich stimme absolut zu, aber für diejenigen, die glauben, dass das ursprüngliche Problem niemals auftauchen würde, wenn wir gutes Design hätten, ist hier eine zusätzliche Frage:

Die Problemdefinition lautet wie folgt: Sie haben eine Datenquelle, in der Zahlen als Strings gespeichert sind . Diese Quelle kann eine XML-Datei, eine Webseite oder ein Desktop-Fenster mit 2 Bearbeitungsfeldern sein.

Ihr Ziel ist es, die Logik zu implementieren, die diese 2 Strings benötigt, sie in ints konvertiert und das Meldungsfeld "Die Summe ist xxx" anzeigt.

Unabhängig davon, mit welchem ​​Ansatz Sie dies entwerfen / implementieren, haben Sie diese zwei Punkte innerer Funktionalität :

  1. Ein Ort , wo Sie konvertieren Stringzuint
  2. Ein Ort, an dem Sie 2 ints hinzufügen

Die Hauptfrage meines ursprünglichen Beitrags lautet:

Integer.parseInt()erwartet, dass die richtige Zeichenfolge übergeben wird. Wenn Sie eine fehlerhafte Zeichenfolge übergeben , bedeutet dies, dass Ihr Programm falsch ist (nicht " Ihr Benutzer ist ein Idiot"). Sie müssen den Code implementieren, in dem Sie einerseits Integer.parseInt () mit MUST-Semantik haben und andererseits mit den Fällen einverstanden sein müssen, in denen die Eingabe falsch ist - SOLLTE Semantik .

Also, kurz: wie kann ich implementieren SOLL Semantik , wenn ich nur haben MUST Bibliotheken .


13
Das ist keine dumme Frage. Eigentlich ist es ziemlich gut! Ich bin mir nicht ganz sicher, welche Option ich wählen würde.
Martin

1
Zu Ihrem Update: Ja, nach dem Fail-Fast-Prinzip wäre dies auch nicht unbedingt eine schlechte Sache.
Johan Sjöberg

1
Ich stimme Martin zu. Dies ist einer der Aspekte der Java-Programmierung, der am wenigsten verstanden wird und einige Best Practices erfordert. Dies kann durch das Fehlen von Seiten zu diesem Thema gesehen werden, von denen außer O'Reilly nur sehr wenige sagen: "So sollte es gemacht werden".
James P.

2
Eigentlich ist das eine ausgezeichnete Frage.
Chris Cudmore

1
Gute Frage! Auch einige gute Antworten aufgeworfen: D
Kheldar

Antworten:


35

Das ist eine gute Frage. Ich wünschte, mehr Menschen würden über solche Dinge nachdenken.

IMHO ist es akzeptabel, ungeprüfte Ausnahmen auszulösen, wenn Ihnen Müllparameter übergeben wurden.

Im Allgemeinen sollten Sie nicht werfen, BadDataExceptionda Sie keine Ausnahmen verwenden sollten, um den Programmfluss zu steuern. Ausnahmen sind für das Außergewöhnliche. Aufrufer Ihrer Methode können wissen, bevor sie sie aufrufen, ob ihre Zeichenfolgen Zahlen sind oder nicht. Daher ist das Übergeben von Müll vermeidbar und kann daher als Programmierfehler betrachtet werden. Dies bedeutet, dass es in Ordnung ist, ungeprüfte Ausnahmen auszulösen.

In Bezug auf die Deklaration ist throws NumberFormatExceptiondies nicht so nützlich, da nur wenige dies bemerken, da die NumberFormatException deaktiviert ist. IDEs können jedoch davon Gebrauch machen und anbieten, try/catchkorrekt einzuwickeln . Eine gute Option ist die Verwendung von Javadoc, z.

/**
 * Adds two string numbers
 * @param a
 * @param b
 * @return
 * @throws NumberFormatException if either of a or b is not an integer
 */
public static int sum(String a, String b) throws NumberFormatException {
    int x = Integer.parseInt(a); 
    int y = Integer.parseInt(b); 
    return x + y;
}

BEARBEITET :
Die Kommentatoren haben gültige Punkte gemacht. Sie müssen überlegen, wie dies verwendet wird und wie Ihre App insgesamt gestaltet ist.

Wenn die Methode überall verwendet wird und es wichtig ist, dass alle Aufrufer Probleme behandeln, deklarieren Sie die Methode als ausgelöste Ausnahme (was Aufrufer dazu zwingt, sich mit Problemen zu befassen), aber den Code mit try/catchBlöcken überladen .

Wenn wir diese Methode andererseits mit Daten verwenden, denen wir vertrauen, deklarieren Sie sie wie oben, da nicht erwartet wird, dass sie jemals explodieren und Sie die Code-Unordnung von im Wesentlichen unnötigen try/catchBlöcken vermeiden .


6
Das Problem ist, dass ungeprüfte Ausnahmen häufig ignoriert werden und Ihren Anrufstapel durchdringen und in Teilen Ihrer App, die keine Ahnung haben, was darunter liegt, Chaos anrichten. Die Frage ist wirklich, welches Codebit prüfen soll, ob die Eingabe gültig ist oder nicht.
G_H

1
@G_H hat einen Punkt. In den Java-Tutorials heißt es: "Wenn von einem Client vernünftigerweise erwartet werden kann, dass er von einer Ausnahme wiederhergestellt wird, machen Sie ihn zu einer aktivierten Ausnahme. Wenn ein Client nichts tun kann, um die Ausnahme wiederherzustellen, machen Sie ihn zu einer nicht aktivierten Ausnahme." Die Frage ist, wo ein RuntimeExceptionbehandelt werden soll? Sollte es der Anrufer sein oder sollte die Ausnahme schweben bleiben? Wenn ja, wie soll damit umgegangen werden?
James P.

1
Um dies teilweise zu beantworten, habe ich zwei Ansätze gesehen: Der erste besteht darin, Exceptionsvon niedrigeren Ebenen abzufangen und sie in Ausnahmen höherer Ebene einzuschließen, die für den Endbenutzer aussagekräftiger sind, und der zweite darin, einen nicht erfassten Ausnahmebehandler zu verwenden, der initialisiert werden kann der Anwendungsstarter.
James P.

2
IMHO ist die NumberFormatException im javaDoc viel wichtiger. Das Einfügen in die throwsKlausel ist eine nette Ergänzung, aber nicht erforderlich.
Dorus

3
Zu "Aufrufer Ihrer Methode können wissen, bevor sie sie aufrufen, ob ihre Zeichenfolgen Zahlen sind oder nicht, sodass das Weitergeben von Müll vermeidbar ist" : Das ist nicht wirklich wahr. Die einzige einfache Möglichkeit, um zu überprüfen, ob ein String als int analysiert wird, besteht darin, ihn auszuprobieren. Obwohl Sie möglicherweise einige Vorabprüfungen durchführen möchten, ist die genaue Überprüfung eine ziemliche PITA.
Maaartinus

49

Meiner Meinung nach wäre es vorzuziehen, die Ausnahmelogik so weit wie möglich zu behandeln. Daher würde ich die Unterschrift vorziehen

 public static int sum(int a, int b);

Mit Ihrer Methodensignatur würde ich nichts ändern. Entweder du bist

  • Programmgesteuert mit falschen Werten, wobei Sie stattdessen Ihren Producer-Algorithmus validieren können
  • oder Senden von Werten aus z. B. Benutzereingaben. In diesem Fall sollte dieses Modul die Validierung durchführen

Daher wird die Ausnahmebehandlung in diesem Fall zu einem Dokumentationsproblem .


4
Ich mag das. Es zwingt den Benutzer, dem Vertrag zu folgen, und lässt die Methode nur eines tun.
Chris Cudmore

Ich verstehe nicht, wie sich die Verwendung dieser Methode von der des Benutzers a + b unterscheidet. Warum brauchen wir diese Methode?
Swati

4
@ Swati: Ich denke, es ist ein Beispiel , das eine großartige Technik ist, um Dinge einfach zu zeigen. Die Summenmethode könnte auch myVeryComplicatedMethodWhichComputesPhoneNumberOfMyIdealMatchGirl (int myID, int myLifeExpectancy) sein ...
Kheldar

3
Stimme hier voll und ganz zu. Eine sumFunktion, die zwei Zahlen erwartet, sollte zwei Zahlen erhalten. Die Art und Weise, wie Sie diese erhalten haben, hängt nicht mit der sumFunktion zusammen. Trennen Sie Ihre Logik richtig . Also würde ich dies mit einem Designproblem in Verbindung bringen.
c00kiemon5ter

5

Nummer 4. Wie angegeben, sollte diese Methode keine Zeichenfolgen als Parameter verwenden, sondern Ganzzahlen. In diesem Fall (da Java umbrochen wird, anstatt überzulaufen) besteht keine Möglichkeit einer Ausnahme.

 x = sum(Integer.parseInt(a), Integer.parseInt(b))

ist viel klarer, was gemeint ist als x = sum(a, b)

Sie möchten, dass die Ausnahme so nahe wie möglich an der Quelle (Eingabe) auftritt.

In Bezug auf die Optionen 1 bis 3 definieren Sie keine Ausnahme, da Sie von Ihren Anrufern erwarten, dass sie davon ausgehen, dass Ihr Code ansonsten nicht fehlschlagen kann. Sie definieren eine Ausnahme, um zu definieren, was unter bekannten Fehlerbedingungen geschieht, die für Ihre Methode eindeutig sind. Wenn Sie also eine Methode haben, die ein Wrapper um ein anderes Objekt ist und eine Ausnahme auslöst, geben Sie diese weiter. Nur wenn die Ausnahme für Ihre Methode eindeutig ist, sollten Sie eine benutzerdefinierte Ausnahme auslösen (frex, in Ihrem Beispiel, wenn sum nur positive Ergebnisse liefern sollte, wäre es angemessen, dies zu überprüfen und eine Ausnahme auszulösen, wenn andererseits Java Wenn Sie eine Überlaufausnahme auslösen, anstatt sie zu verpacken, geben Sie diese weiter, definieren sie nicht in Ihrer Signatur, benennen sie um oder essen sie.

Update als Antwort auf das Update der Frage:

Also kurz: Wie implementiere ich die Semantik, wenn ich nur MUST-Bibliotheken habe?

Die Lösung hierfür besteht darin, die MUST-Bibliothek zu verpacken und einen SHOULD-Wert zurückzugeben. In diesem Fall eine Funktion, die eine Ganzzahl zurückgibt. Schreiben Sie eine Funktion, die eine Zeichenfolge verwendet und ein Integer-Objekt zurückgibt - entweder funktioniert es oder es gibt null zurück (wie Ints.tryParse von guava). Wenn Ihre Validierung von Ihrer Operation getrennt ist, sollte Ihre Operation ints dauern. Ob Ihre Operation mit Standardwerten aufgerufen wird, wenn Sie eine ungültige Eingabe haben, oder wenn Sie etwas anderes tun, hängt von Ihren Spezifikationen ab - das meiste, was ich dazu sagen kann, ist, dass es wirklich unwahrscheinlich ist, dass der Ort, an dem diese Entscheidung getroffen wird, in der Operation liegt Methode.


Was ist deine Idee hier? Ich werde das gleiche Problem bekommen, auch wenn ich sum(int, int)und habe parseIntFromString(String). Um die gleiche Funktionalität zu erhalten, muss ich in beiden Fällen einen Code schreiben, in dem 2 Aufrufe an parseIntFromString()und 1 Aufruf an vorhanden sind sum(). Betrachten Sie diesen Fall, wenn es für Sie sinnvoll ist - ich sehe keinen Unterschied vom Standpunkt des ursprünglichen Problems.
Andrey Agibalov

@ loki2302: Der Punkt ist, dass der Anrufer dann entscheiden kann, welches Verhalten angemessen ist, wenn es keine Nummer ist. Wenn sie keine Fehlerprüfung durchführen, tritt der Fehler einen Schritt näher an der Stelle auf, an der der Wert zugewiesen wurde. Für Debugging-Zwecke ist das Debuggen umso einfacher, je näher die Zuweisung liegt. Und es ist wahrscheinlicher, dass Sie den entsprechenden Komponententest für den Anrufer nicht schreiben, wenn Sie TDD durchführen. Grundsätzlich möchten Sie in Methode x keine Zeichenfolge angeben, die eine Zahl sein soll, und dann lösen 5 Klassen und 20 Methodenaufrufe eine Ausnahme aus, wenn Sie versuchen, eine Zahl zu behandeln.
jmoreno

Ich verstehe es nicht Versuchen Sie zu sagen, dass die Bereitstellung einer Schnittstelle von int sum(String, String)in der Realität niemals möglich ist?
Andrey Agibalov

1
@ loki2302: Angesichts des gezeigten Codes wäre es möglich, aber eine schlechte Idee. Wenn die Zahl in der Zeichenfolge ein Wort sein könnte, bei dem "2", "zwei", "dos", "deux", "zwo" alle gleich behandelt werden sollten, wäre diese Signatur angemessen. Die Methode erhält jedoch zwei Zeichenfolgen und behandelt sie als Ganzzahlen. Warum sollten Sie das jemals tun wollen? Es ist eine schlechte Idee.
jmoreno

2
@ loki2302: Sie haben die Antwort akzeptiert, dass es in Ordnung ist, eine ungeprüfte Ausnahme auszulösen, wenn Müll übergeben wird, aber der Sinn einer stark typisierten Sprache besteht darin, zu verhindern, dass Müll übergeben wird. Eine Methode zu haben, die erwartet, dass eine Zeichenfolge immer ein ganzzahliger Wert ist, ist nur ein Problem. Selbst Integer.parseInt geht damit nicht gut um (eine Ausnahme bei der zu erwartenden Eingabe ist schlecht. Die Integer.TryParse-Methode von .Net ist viel besser, obwohl das Fehlen eines out-Parameters in Java etwas unpraktisch ist).
Jmoreno

3

1. Ich sollte NumberFormatException als Teil der Signatur der Methode angeben.

Ich glaube schon. Es ist eine schöne Dokumentation.

2. Ich sollte meine eigene geprüfte Ausnahme (BadDataException) definieren, NumberFormatException innerhalb der Methode behandeln und sie erneut als BadDataException auslösen.

Manchmal ja. Die überprüften Ausnahmen werden in einigen Fällen als besser angesehen, aber die Arbeit mit ihnen ist eine ziemliche PITA. Aus diesem Grund verwenden viele Frameworks (z. B. Hibernate) nur Laufzeitausnahmen.

3. Ich sollte meine eigene geprüfte Ausnahme (BadDataException) definieren, beide Zeichenfolgen wie reguläre Ausdrücke validieren und meine BadDataException auslösen, wenn sie nicht übereinstimmt.

Noch nie. Mehr Arbeit, weniger Geschwindigkeit (es sei denn, Sie erwarten, dass das Auslösen der Ausnahme eine Regel ist) und überhaupt kein Gewinn.

4. Deine Idee?

Überhaupt keine.


2

Nr. 4.

Ich denke, ich würde die Methode überhaupt nicht ändern. Ich würde versuchen, die aufrufende Methode oder höher im Stack-Trace zu umgehen, wenn ich mich in einem Kontext befinde, in dem ich mich mit Geschäftslogik ordnungsgemäß von der Ausnahme erholen kann.

Ich würde # 3 nicht mit Sicherheit machen, da ich es für übertrieben halte.


2

Angenommen, das, was Sie schreiben, wird (wie eine API) von jemand anderem verwendet, dann sollten Sie mit 1 gehen. NumberFormatException dient speziell zum Zweck der Übermittlung solcher Ausnahmen und sollte verwendet werden.


2
  1. Zuerst müssen Sie sich fragen, muss sich der Benutzer meiner Methode Sorgen um die Eingabe falscher Daten machen oder wird von ihm erwartet, dass er die richtigen Daten eingibt (in diesem Fall String). Diese Erwartung wird auch als Design by Contract bezeichnet .

  2. und 3. Ja, Sie sollten wahrscheinlich BadDataException definieren oder noch besser einige der aufregenden wie NumberFormatException verwenden, sondern die Standardnachricht anzeigen lassen. Fangen Sie NumberFormatException in der Methode ab und werfen Sie sie erneut mit Ihrer Nachricht, ohne zu vergessen, dass der ursprüngliche Stack-Trace enthalten ist.

  3. Es hängt von der Situation ab, aber ich würde wahrscheinlich NumberFormatException mit einigen zusätzlichen Informationen erneut auslösen. Und es muss auch eine Javadoc-Erklärung geben, wofür die erwarteten Werte sindString a, String b


1

Hängt stark von dem Szenario ab, in dem Sie sich befinden.

Fall 1. Es sind immer Sie, die den Code debuggen, und niemand anderes und eine Ausnahme verursachen keine schlechte Benutzererfahrung

Wirf die Standard NumberFormatException

Fall 2: Code sollte äußerst wartbar und verständlich sein

Definieren Sie Ihre eigene Ausnahme und fügen Sie beim Auslösen viel mehr Daten zum Debuggen hinzu.

Sie brauchen keine Regex-Prüfungen, da dies bei schlechten Eingaben ohnehin zur Ausnahme führen wird.

Wenn es ein Code auf Produktionsebene wäre, wäre meine Idee, mehr als eine benutzerdefinierte Ausnahme zu definieren, wie z

  1. Ausnahme vom Zahlenformat
  2. Überlaufausnahme
  3. Null Ausnahme etc ...

und mit all diesen getrennt umgehen


1
  1. Sie können dies tun, um zu verdeutlichen, dass dies bei falscher Eingabe passieren kann. Es kann jemandem helfen, der Ihren Code verwendet, sich daran zu erinnern, wie er mit dieser Situation umgegangen ist. Insbesondere machen Sie deutlich, dass Sie im Code nicht selbst damit umgehen oder stattdessen einen bestimmten Wert zurückgeben. Natürlich sollte das JavaDoc dies auch klarstellen.
  2. Nur wenn Sie den Anrufer zwingen möchten, eine aktivierte Ausnahme zu behandeln.
  3. Das scheint übertrieben. Verlassen Sie sich auf das Parsen, um schlechte Eingaben zu erkennen.

Insgesamt ist eine NumberFormaException deaktiviert, da erwartet wird, dass korrekt analysierbare Eingaben bereitgestellt werden. Die Eingabevalidierung ist etwas, mit dem Sie umgehen sollten. Das eigentliche Parsen der Eingabe ist jedoch der einfachste Weg, dies zu tun. Sie können Ihre Methode einfach so lassen, wie sie ist, und in der Dokumentation warnen, dass eine korrekte Eingabe erwartet wird und jeder, der Ihre Funktion aufruft, beide Eingaben validieren sollte, bevor er sie verwendet.


1

Jedes außergewöhnliche Verhalten sollte in der Dokumentation geklärt werden. Entweder sollte angegeben werden, dass diese Methode einen speziellen Wert zurückgibt, falls ein Fehler auftritt (z. B. nulldurch Ändern des Rückgabetyps in Integer), oder es sollte Fall 1 verwendet werden. Wenn der Benutzer es explizit in der Signatur der Methode hat, kann er es ignorieren, wenn er auf andere Weise für korrekte Zeichenfolgen sorgt. Es ist jedoch offensichtlich, dass die Methode diese Art von Fehler nicht selbst behandelt.


1

Beantworten Sie Ihre aktualisierte Frage.

Ja, es ist völlig normal, "Überraschungs" -Ausnahmen zu bekommen. Denken Sie an alle Laufzeitfehler, die beim Programmieren aufgetreten sind.

e.g ArrayIndexOutofBound

Auch eine häufige Überraschungsausnahme von der für jede Schleife.

ConcurrentModificationException or something like that

1

Obwohl ich der Antwort zustimme, dass die Laufzeitausnahme aus Sicht des Designs und der Benutzerfreundlichkeit durchgelassen werden darf, ist es eine gute Idee, sie in eine IllegalArgumentException zu packen, anstatt sie als NumberFormatException zu werfen. Dies macht dann den Vertrag Ihrer Methode klarer, in dem erklärt wird, dass ein rechtswidriges Argument an sie übergeben wurde, aufgrund dessen eine Ausnahme ausgelöst wurde.

In Bezug auf das Update der Frage "Stellen Sie sich vor, es ist kein Open-Source-Framework, das Sie aus irgendeinem Grund verwenden sollten. Sie sehen sich die Signatur der Methode an und denken:" OK, es wird nie ausgelöst ". Dann haben Sie eines Tages eine Ausnahme . Es ist normal?" Das Javadoc Ihrer Methode sollte immer das Verhalten Ihrer Methode (Vor- und Nacheinschränkungen) ausdrücken. Denken Sie an die Zeilen von say-Auflistungsschnittstellen, in denen, wenn eine Null nicht zulässig ist, der Javadoc sagt, dass eine Nullzeigerausnahme ausgelöst wird, obwohl sie niemals Teil der Methodensignatur ist.


2
NumberFormatException ist eine Unterklasse von IllegalArgumentException, daher fügt dieser Wrapping keine Informationen hinzu.
Don Roby

was es bedeutet, dass die Ausnahme so wie sie ist durchgesickert werden kann (da in diesem Fall nfe bereits eine Ausnahme für illegale Argumente ist) und es eine generische Behandlung geben kann, um mit illegalen Argumenten irgendwo oben in der Aufrufhierarchie umzugehen. Wenn dies also ein Beispiel wäre, in dem die Argumente vom Benutzer übergeben wurden, könnte es einen generischen Code geben, der die gesamte Behandlung für illegale Argumente umschließt und den Benutzer darüber informiert.
Scorpion

1

Wenn Sie über gute Java-Praxis sprechen, ist es meiner Meinung nach immer besser

  • Um die ungeprüfte Ausnahme zu behandeln, analysieren Sie sie und verwenden Sie eine benutzerdefinierte ungeprüfte Ausnahme.

  • Während Sie eine benutzerdefinierte, nicht aktivierte Ausnahme auslösen, können Sie die Ausnahmemeldung hinzufügen, die Ihr Client verstehen kann, und auch die Stapelverfolgung der ursprünglichen Ausnahme drucken

  • Es ist nicht erforderlich, eine benutzerdefinierte Ausnahme als "Auslöser" zu deklarieren, da diese deaktiviert ist.

  • Auf diese Weise verletzen Sie nicht die Verwendung der nicht aktivierten Ausnahmen, für die gleichzeitig der Client des Codes den Grund und die Lösung für die Ausnahme leicht verstehen würde.

  • Auch eine ordnungsgemäße Dokumentation in Java-Doc ist eine gute Vorgehensweise und hilft sehr.


1

Ich denke, es hängt von Ihrem Zweck ab, aber ich würde es mindestens dokumentieren:

/**
 * @return the sum (as an int) of the two strings
 * @throws NumberFormatException if either string can't be converted to an Integer
 */
public static int sum(String a, String b)
  int x = Integer.parseInt(a);
  int y = Integer.parseInt(b);
  return x + y;
}

Oder nehmen Sie eine Seite aus dem Java-Quellcode für die Klasse java.lang.Integer:

public static int parseInt(java.lang.String string) throws java.lang.NumberFormatException;

1

Wie wäre es mit dem Eingabevalidierungsmuster, das von Googles 'Guava'-Bibliothek oder Apaches' Validator'-Bibliothek implementiert wurde ( Vergleich )?

Nach meiner Erfahrung wird es als bewährte Methode angesehen, die Parameter einer Funktion zu Beginn der Funktion zu validieren und gegebenenfalls Ausnahmen auszulösen.

Ich würde diese Frage auch als weitgehend sprachunabhängig betrachten. Die "gute Praxis" hier würde für alle Sprachen gelten, die Funktionen haben, die Parameter annehmen können, die möglicherweise gültig sind oder nicht.


1

Ich denke, Ihr allererster Satz von "Eine ziemlich dumme Frage" ist sehr relevant. Warum sollten Sie überhaupt eine Methode mit dieser Signatur schreiben? Ist es überhaupt sinnvoll, zwei Zeichenfolgen zu summieren? Wenn die aufrufende Methode zwei Zeichenfolgen summieren möchte, liegt es in der Verantwortung der aufrufenden Methode, sicherzustellen, dass sie gültige Ints sind, und sie vor dem Aufrufen der Methode zu konvertieren.

Wenn die aufrufende Methode in diesem Beispiel die beiden Zeichenfolgen nicht in eine int konvertieren kann, kann sie verschiedene Aktionen ausführen. Es hängt wirklich davon ab, auf welcher Ebene diese Summierung auftritt. Ich gehe davon aus, dass die String-Konvertierung dem Front-End-Code sehr nahe kommt (wenn sie ordnungsgemäß durchgeführt wurde), sodass Fall 1 am wahrscheinlichsten ist:

  1. Stellen Sie eine Fehlermeldung ein und beenden Sie die Verarbeitung oder leiten Sie zu einer Fehlerseite um
  2. Rückgabe false (dh es würde die Summe in ein anderes Objekt einfügen und müsste es nicht zurückgeben)
  3. Wirf eine BadDataException, wie du vorschlägst, aber wenn die Summierung dieser beiden Zahlen nicht sehr wichtig ist, ist dies übertrieben, und wie oben erwähnt, ist dies wahrscheinlich ein schlechtes Design, da dies impliziert, dass die Konvertierung am falschen Ort durchgeführt wird

1

Auf diese Frage gibt es viele interessante Antworten. Aber ich möchte noch Folgendes hinzufügen:

Für das Parsen von Zeichenfolgen bevorzuge ich immer "reguläre Ausdrücke". Das Paket java.util.regex hilft uns dabei. Also werde ich mit so etwas enden, das niemals eine Ausnahme auslöst. Es liegt an mir, einen speziellen Wert zurückzugeben, wenn ich einen Fehler feststellen möchte:

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public static int sum(String a, String b) {
  final String REGEX = "\\d"; // a single digit
  Pattern pattern = Pattern.compile(REGEX);
  Matcher matcher = pattern.matcher(a);
  if (matcher.find()) { x = Integer.matcher.group(); }
  Matcher matcher = pattern.matcher(b);
  if (matcher.find()) { y = Integer.matcher.group(); }
  return x + y;
}

Wie man sehen kann, ist der Code nur ein bisschen länger, aber wir können mit dem umgehen, was wir wollen (und Standardwerte für x und y festlegen, steuern, was mit else-Klauseln passiert usw.). Wir könnten sogar eine allgemeinere Transformation schreiben Routine, an die wir Strings übergeben können, Rückgabewerte defaut, REGEX-Code zum Kompilieren, Fehlermeldungen zum Auslösen, ...

Hoffe, es war nützlich.

Warnung: Ich konnte diesen Code nicht testen. Bitte entschuldigen Sie eventuelle Syntaxprobleme.


1
Sprechen wir über Java? Was ist Integer.matcher? privateVariable innerhalb der Methode? Fehlende ()für ifs, fehlt viel ;, x, ynicht erklärt, matcherzweimal erklärt, ...
user85421

In der Tat, Carlos, ich habe es in Eile getan und konnte es, wie gesagt, nicht sofort testen. Es tut uns leid. Ich wollte die Regex-Methode zeigen.
Louis

OK, aber dies löst nicht das Problem mit NumberFormatException - der Hauptfrage IMO - (vorausgesetzt, Integer.matcher.group()das soll sein Integer.parseInt(matcher.group()))
user85421

0

Sie sind mit diesem Problem konfrontiert, weil Benutzerfehler zu tief in den Kern der Anwendung eindringen und teilweise auch, weil Sie Java-Datentypen missbrauchen.

Sie sollten eine klarere Trennung zwischen Validierung von Benutzereingaben und Geschäftslogik haben, die richtige Datentypisierung verwenden und dieses Problem wird von selbst verschwinden.

Tatsache ist, dass die Semantik von Integer.parseInt()bekannt ist - es ist der Hauptzweck, gültige ganze Zahlen zu analysieren . Ihnen fehlt ein expliziter Schritt zur Validierung / Analyse von Benutzereingaben.

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.