Frage

Sehen als Java nicht auf NULL festlegbaren Typen hat, noch hat es eine TryParse (), Wie gehen Sie mit der Eingabevalidierung ohne eine Ausnahme zu werfen?

Der üblicher 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 kann einen regulären Ausdruck verwenden, um zu überprüfen, ob es parseable ist, aber das scheint wie eine Menge Overhead als auch.

Was ist die beste Praxis, diese Situation für den Umgang mit?

EDIT: Hintergrund: Es gab auf SO über die Ausnahmebehandlung viel geredet, und die allgemeine Haltung ist, dass Ausnahmen nur für unerwartete Szenarien verwendet werden. Aber ich denke, schlechte Benutzereingabe erwartet wird, nicht selten. Ja, es ist wirklich ein akademischer Punkt.

Weitere Edits:

Einige der Antworten zeigen genau das, was mit so falsch ist. Sie ignorieren die Frage gestellt wird, und eine andere Frage beantworten, die nichts damit zu tun hat. Die Frage stellt sich nicht um Übergang zwischen den Schichten. Die Frage ist nicht gefragt, was zurück, wenn die Zahl un-parseable ist. Für alle wissen Sie, val = Integer.MIN_VALUE; genau die richtige Wahl für die Anwendung ist, dass dieser vollständig kontextfreie Code-Schnipsel aus wurde nehmen.

War es hilfreich?

Lösung

Das ist so ziemlich das, obwohl MIN_VALUE Rückkehr Art fraglich ist, es sei denn, Sie sicher sind, dann ist es das Richtige für verwenden, was Sie im Wesentlichen als ein Fehlercode. Zumindest würde ich den Fehlercode Verhalten dokumentieren, though.

ebenfalls nützlich sein kann (je nach Anwendung), um den schlechten Eingang anmelden, damit Sie verfolgen können.

Andere Tipps

Ich fragte wenn es Open-Source Dienstprogramm-Bibliotheken, die Methoden hatten diese Analyse für Sie tun und die Antwort ist ja!

Apache Commons Lang können Sie NumberUtils.toInt :

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

Google Guava Ints.tryParse :

// 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);

Es gibt keine Notwendigkeit, Ihre eigenen Methoden zu schreiben, Zahlen zu analysieren, ohne Ausnahmen zu werfen.

Für Benutzer gelieferten Daten ist Integer.parseInt in der Regel die falsche Methode, weil sie nicht internationisation unterstützt. Das java.text Paket ist Sie (ausführlich) 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 ...
}

Was ist das Problem mit Ihrem Ansatz? Ich glaube nicht, dass das so tun, wird überhaupt die Leistung Ihrer Anwendung verletzen. Das ist der richtige Weg, es zu tun. Sie nicht optimieren vorzeitig .

Ich bin sicher, dass es schlechter Stil ist, aber ich habe eine Reihe von statischen Methoden auf einer Dienstprogramme Klasse, die Dinge wie Utilities.tryParseInt(String value) tun, die 0 zurück, wenn der String unparseable und Utilities.tryParseInt(String value, int defaultValue), die Sie einen Wert angeben kann, verwenden, wenn parseInt() löst eine Ausnahme aus.

Ich glaube, es gibt Zeiten, in denen einen bekannten Wert auf schlechten Eingang Rückkehr durchaus akzeptabel ist. Ein sehr konstruiertes Beispiel: Sie fragen den Benutzer nach einem Datum im Format YYYYMMDD und sie geben Ihnen schlecht Eingang. Es kann durchaus akzeptabel sein, etwas zu tun, wie Utilities.tryParseInt(date, 19000101) oder Utilities.tryParseInt(date, 29991231); auf den Programmanforderungen abhängig.

Ich werde den Punkt neu zu formulieren, die stinkyminky wurde zum Boden des Pfostens zu machen:

Eine allgemein gut akzeptiert Ansatz Validierung von Benutzereingaben (oder Eingabe von Konfigurationsdateien, etc ...) ist die Validierung zu verwenden, vor dem eigentlichen Verarbeitung der Daten. In die meisten Fällen ist dies ein gutes Design zu bewegen, auch wenn es in mehreren Anrufen zu Parsing-Algorithmen führen kann.

Sobald Sie wissen, dass Sie richtig die Benutzereingabe überprüft haben, und es sicher ist es, zu analysieren und zu ignorieren, melden oder wandeln die Number zu Runtime.

Beachten Sie, dass dieser Ansatz erfordert, dass Sie Ihr Modell in zwei Stücke zu berücksichtigen: das Geschäftsmodell (Wo wir eigentlich egal Werte in int oder float-Format hat) und die Benutzeroberfläche Modell (wo wir wirklich zulassen wollen, um den Benutzer zu setzen in was auch immer sie wollen).

für die Daten in der Reihenfolge von der Benutzeroberfläche Modell auf das Geschäftsmodell zu migrieren, muss es einen Validierungsschritt durchlaufen (das auf einem Feld für Feld Basis auftreten können, aber die meisten Szenarien rufen zur Validierung auf das gesamte Objekt, das ist konfiguriert ist).

Wenn die Validierung fehlschlägt, wird der Benutzer mit Feedback präsentiert wird sie zu informieren, was sie falsch gemacht habe und da eine Chance, es zu beheben.

Binding-Bibliotheken wie JGoodies Bindung und JSR 295 machen diese Art der Sache viel einfacher zu implementieren als es klingen mag - und viel Web-Frameworks Konstrukte bieten, die Benutzereingaben von dem eigentlichen Geschäftsmodell trennen, nur Objekte Geschäft bevölkert nach der Validierung abgeschlossen .

Im Hinblick auf die Validierung von Konfigurationsdateien (die andere in einigen Kommentaren präsentiert Anwendungsfall), es ist eine Sache, eine Standard angeben, ob ein bestimmter Wert wird überhaupt keine Angabe - aber wenn die Daten falsch formatiert (jemand Typen ein ‚oh‘ anstelle ein ‚Null‘ - oder sie von MS Word kopiert und all back-Zecken bekamen ein funky Unicode-Zeichen), dann wird eine Art von System-Feedback benötigt (auch wenn es die App nur ist andernfalls durch einen Wurf Runtime-Ausnahme).

Hier ist, wie ich es tun:

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

Dann werden die Nullsignale ungültige Daten. Wenn Sie einen Standardwert möchten, können Sie es ändern:

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

Ich denke, die beste Praxis der Code ist es Ihnen zeigen.

Ich würde nicht für die regex Alternative gehen aufgrund des Aufwands.

Versuchen org.apache.commons.lang.math.NumberUtils.createInteger(String s). Das hat mir sehr geholfen. Es gibt ähnliche Methoden gibt für Doppelzimmer, longs etc.

Sie können einen Integer verwenden, die auf null gesetzt werden kann, wenn Sie einen schlechten Wert haben. Wenn Sie verwenden Java 1.6, wird es automatisch Boxen liefern / Unboxing für Sie.

Reiniger Semantik (Java 8 OptionalInt)

Für Java 8+, würde ich wahrscheinlich RegEx verwenden, um Vorfilter (die Ausnahme zu vermeiden, wie Sie bemerken) und dann das Ergebnis in einem primitiven optional wickelt (mit dem „default“ Problem umgehen):

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

Wenn Sie viele String-Eingänge haben, könnten Sie erwägen, eine IntStream statt OptionalInt zurückkehren, so dass Sie flatMap() können.

Referenzen

Der obige Code ist schlecht, weil es gleichbedeutend wie die folgende ist.

// this is bad
int val = Integer.MIN_VALUE;
try
{
   val = Integer.parseInt(userdata);
}
catch (NumberFormatException ignoreException) { }

Die Ausnahme wird vollständig ignoriert. Auch die magischen Token sind schlecht, weil ein Benutzer in -2147483648 (Integer.MIN_VALUE) passieren kann.

Die allgemeine Parse-able Frage ist nicht von Vorteil. Vielmehr sollte es auf den Kontext relevant sein. Ihre Anwendung hat eine spezifische Anforderung. Sie können Ihre Methode als

definieren
private boolean isUserValueAcceptable(String userData)
{
   return (    isNumber(userData)    
          &&   isInteger(userData)   
          &&   isBetween(userData, Integer.MIN_VALUE, Integer.MAX_VALUE ) 
          );
}

Wo können Sie Dokumentation die Anforderung und Sie erstellen können gut definierte und prüfbare Regeln.

Wenn Sie Ausnahmen vermeiden, indem sie vorher zu testen, wie Sie gesagt haben (isParsable ()), es könnte besser sein -. Aber nicht alle Bibliotheken wurden mit dem im Verstand entworfen

Ich habe Ihren Trick und es saugt, weil Stack-Traces auf meinem Embedded-System gedruckt werden, unabhängig davon, ob Sie sie fangen oder nicht: (

Der Ausnahmemechanismus ist wertvoll, da es der einzige Weg, um eine Statusanzeige in Kombination mit einem Antwortwert zu erhalten. Darüber hinaus wird die Statusanzeige standardisiert. Wenn es einen Fehler erhalten Sie eine Ausnahme. Auf diese Weise müssen Sie sich nicht denken Sie an eine Fehleranzeige. Der Streit ist nicht so sehr mit Ausnahmen, aber mit geprüften Ausnahmen (zum Beispiel diejenigen, müssen Sie fangen oder zu erklären).

Persönlich fühle ich Ihnen eines der Beispiele ausgesucht, wo Ausnahmen wirklich wertvoll sind. Es ist ein häufiges Problem der Benutzer den falschen Wert eingibt, und in der Regel werden Sie müssen zurück an den Benutzer für den richtigen Wert zu erhalten. Sie normalerweise nicht auf den Standardwert zurückgesetzt, wenn Sie den Benutzer fragen; das gibt dem Benutzer den Eindruck, seine Eingabe zählt.

Wenn Sie nicht wollen, mit Ausnahme zu behandeln, wickeln Sie es einfach in einem Runtime (oder abgeleitete Klasse) und es erlaubt Ihnen, die Ausnahme in Ihrem Code zu ignorieren (und Ihre Anwendung töten, wenn er auftritt, das ist auch in Ordnung manchmal ).

Einige Beispiele, wie ich Number Ausnahmen behandeln würde: In Web-App-Konfigurationsdaten:

loadCertainProperty(String propVal) {
  try
  {
    val = Integer.parseInt(userdata);
    return val;
  }
  catch (NumberFormatException nfe)
  { // RuntimeException need not be declared
    throw new RuntimeException("Property certainProperty in your configuration is expected to be " +
                               " an integer, but was '" + propVal + "'. Please correct your " +
                               "configuration and start again");
    // After starting an enterprise application the sysadmin should always check availability
    // and can now correct the property value
  }
}

In einer GUI:

public int askValue() {
  // TODO add opt-out button; see Swing docs for standard dialog handling
  boolean valueOk = false;
  while(!valueOk) {
    try {
      String val = dialog("Please enter integer value for FOO");
      val = Integer.parseInt(userdata);
      return val; 
    } catch (NumberFormatException nfe) {
      // Ignoring this; I don't care how many typo's the customer makes
    }
  }
}

In einem Web-Formular: schicken Sie das Formular an den Benutzer mit einer nützlichen Fehlermeldung und einer Chance zu richtig. Die meisten Frameworks bieten eine standardisierte Art und Weise der Validierung.

Integer.MIN_VALUE als Number ist keine gute Idee.

Sie können Vorschlag Projekt Münze hinzufügen, um dieses Verfahren zu Integer hinzufügen

@Nullable public static Integer parseInteger (String src) ... es wird null für schlechten Eingang zurückkehrt

Dann legen Sie Link zu Ihrem Vorschlag hier und wir alle werden dafür stimmen!

PS: Schauen Sie sich diese http://msdn.microsoft.com/en-us/library/bb397679.aspx Dies ist, wie hässlich und aufgedunsen es sein könnte

Setzen Sie einige, wenn Aussagen vor ihm. if (null! = userdata)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top