it-swarm.com.de

String to Int in Java - Wahrscheinlich schlechte Daten, Ausnahmen müssen vermieden werden

Sehen Sie, dass Java keine nullfähigen Typen hat und auch kein TryParse ().......................................

Der übliche Weg:

String userdata = /*value from gui*/
int val;
try
{
   val = Integer.parseInt(userdata);
}
catch (NumberFormatException nfe)
{
   // bad data - set to sentinel
   val = Integer.MIN_VALUE;
}

Ich könnte einen Regex verwenden, um zu überprüfen, ob er analysiert werden kann, aber das scheint auch viel Aufwand zu sein.

Was ist die beste Vorgehensweise, um mit dieser Situation umzugehen?

EDIT: Begründung: Es wurde viel über SO über die Behandlung von Ausnahmen gesprochen, und die allgemeine Einstellung ist, dass Ausnahmen nur für unerwartete Szenarien verwendet werden sollten. Ich denke jedoch, dass schlechte Benutzereingaben erwartet werden, nicht selten. Ja, es ist wirklich ein akademischer Punkt.

Weitere Bearbeitungen: 

Einige Antworten zeigen genau, was mit SO falsch ist. Sie ignorieren die Frage und beantworten eine andere Frage, die nichts damit zu tun hat. Die Frage fragt nicht nach dem Übergang zwischen den Schichten. Die Frage stellt nicht die Frage, was zurückgegeben werden soll, wenn die Nummer nicht analysiert werden kann. Für alles, was Sie wissen, ist val = Integer.MIN_VALUE; ist genau die richtige Option für die Anwendung, aus der dieses vollständig kontextfreie Code-Snippet entnommen wurde.

37
Chris Cudmore

Das ist so ziemlich alles, auch wenn MIN_VALUE zurückgegeben wird, ist fragwürdig, es sei denn, Sie sind sich sicher, dass es das Richtige für das ist, was Sie als Fehlercode verwenden. Zumindest würde ich das Verhalten des Fehlercodes dokumentieren.

Kann auch nützlich sein (abhängig von der Anwendung), um die fehlerhaften Eingaben zu protokollieren, damit Sie nachverfolgen können.

16
Steve B.

Ich fragte ob es Open-Source-Dienstbibliotheken gab, die Methoden hatten, um diese Analyse für Sie durchzuführen und die Antwort ist Ja!

Von Apache Commons Lang können Sie NumberUtils.toInt verwenden:

// returns defaultValue if the string cannot be parsed.
int i = org.Apache.commons.lang.math.NumberUtils.toInt(s, defaultValue);

Von Google Guava können Sie Ints.tryParse verwenden:

// returns null if the string cannot be parsed
// Will throw a NullPointerException if the string is null
Integer i = com.google.common.primitives.Ints.tryParse(s);

Sie müssen keine eigenen Methoden schreiben, um Zahlen zu analysieren, ohne Ausnahmen zu werfen.

27

Für vom Benutzer eingegebene Daten ist Integer.parseInt normalerweise die falsche Methode, da keine Internation unterstützt wird. Das Java.text-Paket ist Ihr (verbose) Freund.

try {
    NumberFormat format = NumberFormat.getIntegerInstance(locale);
    format.setParseIntegerOnly(true);
    format.setMaximumIntegerDigits(9);
    ParsePosition pos = new ParsePosition(0);
    int val = format.parse(str, pos).intValue();
    if (pos.getIndex() != str.length()) {
        // ... handle case of extraneous characters after digits ...
    }
    // ... use val ...
} catch (Java.text.ParseFormatException exc) {
    // ... handle this case appropriately ...
}
17

Was ist das Problem bei Ihrem Ansatz? Ich glaube nicht, dass dies die Leistung Ihrer Anwendung beeinträchtigen wird. Das ist der richtige Weg. Nicht vorzeitig optimieren .

11
asterite

Ich bin mir sicher, dass es eine schlechte Form ist, aber ich habe eine Reihe statischer Methoden für eine Utilities-Klasse, die Dinge wie Utilities.tryParseInt(String value) ausführt, die 0 zurückgibt, wenn der String unparseable ist, und Utilities.tryParseInt(String value, int defaultValue), die es Ihnen ermöglicht, einen zu verwendenden Wert anzugeben, wenn parseInt() eine Ausnahme auslöst .

Ich glaube, es gibt Zeiten, in denen die Rückgabe eines bekannten Wertes bei fehlerhafter Eingabe durchaus akzeptabel ist. Ein sehr durchdachtes Beispiel: Sie fragen den Benutzer nach einem Datum im Format JJJJMMTT und geben Ihnen eine schlechte Eingabe. Abhängig von den Programmanforderungen kann es durchaus akzeptabel sein, etwas wie Utilities.tryParseInt(date, 19000101) oder Utilities.tryParseInt(date, 29991231); zu tun.

6
Grant Wagner

Ich werde den Punkt wiederholen, den Stinkyminky am Ende des Pfostens gemacht hat:

Ein allgemein akzeptierter Ansatz zur Validierung von Benutzereingaben (oder Eingaben aus Konfigurationsdateien usw.) besteht darin, die Validierung vor der eigentlichen Verarbeitung der Daten zu verwenden. In den meisten Fällen ist dies ein guter Entwurfsschritt, obwohl dies zu mehreren Aufrufen von Parsing-Algorithmen führen kann.

Wenn Sie wissen, dass Sie die Benutzereingabe ordnungsgemäß überprüft haben, dann ist es sicher, sie zu parsen und die NumberFormatException zu ignorieren, zu protokollieren oder in RuntimeException zu konvertieren.

Beachten Sie, dass Sie bei diesem Ansatz Ihr Modell in zwei Teilen betrachten müssen: das Geschäftsmodell (wo wir uns wirklich Gedanken über Werte im Int- oder Float-Format machen) und das Benutzeroberflächenmodell (wo wir dem Benutzer wirklich erlauben wollen, was er möchte.) wollen).

Damit die Daten vom Benutzeroberflächenmodell in das Geschäftsmodell migriert werden können, müssen sie einen Validierungsschritt durchlaufen (dies kann Feld für Feld geschehen, die meisten Szenarien erfordern jedoch eine Überprüfung des gesamten konfigurierten Objekts). .

Wenn die Validierung fehlschlägt, wird dem Benutzer ein Feedback angezeigt, in dem er darüber informiert wird, was er falsch gemacht hat, und er hat die Möglichkeit, das Problem zu beheben.

Bindungsbibliotheken wie JGoodies Binding und JSR 295 machen das Implementieren viel einfacher, als es vielleicht klingt - und viele Web-Frameworks enthalten Konstrukte, die Benutzereingaben vom eigentlichen Geschäftsmodell trennen. Nach Abschluss der Validierung werden nur Business-Objekte aufgefüllt.

In Bezug auf die Validierung von Konfigurationsdateien (der andere Anwendungsfall, der in einigen Kommentaren dargestellt wird), ist es eine Sache, einen Standardwert anzugeben, wenn ein bestimmter Wert überhaupt nicht angegeben ist. Wenn die Daten jedoch falsch formatiert sind (jemand schreibt ein ''). ach 'statt einer' Null '- oder sie wurden aus MS Word kopiert und alle Back-Ticks erhielten einen unkonventionellen Unicode-Charakter), dann ist eine Art Systemrückmeldung erforderlich (selbst wenn die App nur durch Ausführung einer Laufzeitausnahme ausfällt) .

3
Kevin Day

So mache ich es:

public Integer parseInt(String data) {
  Integer val = null;
  try {
    val = Integer.parseInt(userdata);
  } catch (NumberFormatException nfe) { }
  return val;
}

Dann signalisiert die Null ungültige Daten. Wenn Sie einen Standardwert wünschen, können Sie ihn wie folgt ändern:

public Integer parseInt(String data,int default) {
  Integer val = default;
  try {
    val = Integer.parseInt(userdata);
  } catch (NumberFormatException nfe) { }
  return val;
}
2
noah

Versuchen Sie es mit org.Apache.commons.lang.math.NumberUtils.createInteger(String s). Das hat mir sehr geholfen. Es gibt ähnliche Methoden für Doubles, Longs etc.

1
Zlosny

Ich denke, die beste Vorgehensweise ist der Code, den Sie zeigen.

Ich würde nicht für die Regex-Alternative wegen des Overheads gehen.

1
Shimi Bandiel

Cleaner-Semantik (Java 8 OptionalInt)

Für Java 8+ würde ich wahrscheinlich RegEx verwenden, um vorab zu filtern (um die Ausnahme zu vermeiden, wie Sie bemerkt haben) und dann das Ergebnis in ein primitives optionales Element zu verpacken (um das "Standard" -Problem zu behandeln):

public static OptionalInt toInt(final String input) {
    return input.matches("[+-]?\\d+") 
            ? OptionalInt.of(Integer.parseInt(input)) 
            : OptionalInt.empty();
}

Wenn Sie viele String-Eingaben haben, können Sie in Betracht ziehen, anstelle von IntStream eine OptionalInt zurückzugeben, damit Sie flatMap() können.

Verweise

0
AjahnCharles

Sie können eine Ganzzahl verwenden, die bei einem ungültigen Wert auf null gesetzt werden kann. Wenn Sie Java 1.6 verwenden, wird für Sie das automatische Boxen/Unboxing bereitgestellt.

0
Milhous