Gute Möglichkeit, Integer.parseInt () zu kapseln

88

Ich habe ein Projekt, in dem wir oft Integer.parseInt()einen String in einen Int konvertieren. Wenn etwas schief geht (zum Beispiel ist das Stringkeine Zahl, sondern der Buchstabe aoder was auch immer), löst diese Methode eine Ausnahme aus. Wenn ich jedoch überall Ausnahmen in meinem Code behandeln muss, sieht dies sehr schnell sehr hässlich aus. Ich möchte dies in eine Methode einfügen, habe jedoch keine Ahnung, wie ein sauberer Wert zurückgegeben werden soll, um zu zeigen, dass die Konvertierung fehlgeschlagen ist.

In C ++ hätte ich eine Methode erstellen können, die einen Zeiger auf ein int akzeptiert und die Methode selbst true oder false zurückgeben lässt. Soweit ich weiß, ist dies in Java jedoch nicht möglich. Ich könnte auch ein Objekt erstellen, das eine True / False-Variable und den konvertierten Wert enthält, aber dies scheint auch nicht ideal zu sein. Das Gleiche gilt für einen globalen Wert, und dies könnte mir Probleme mit Multithreading bereiten.

Gibt es also einen sauberen Weg, dies zu tun?

Schlechtes Pferd
quelle
Die Zeichen in der Zeichenfolge muss alle Dezimalstellen sein, mit der Ausnahme , dass das erste Zeichen ... . Anstatt Ausnahmen überall im Code zu behandeln, überprüfen Sie einfach das Zeichenfolgenformat, bevor Sie die Analysemethode aufrufen.
Lightman
Es ist nahezu unmöglich, einen regulären Ausdruck zu schreiben, der alle gültigen 32-Bit-Ganzzahlen mit Vorzeichen und keine der ungültigen erfasst. 2147483647 ist legal, int2147483648 nicht.
Seva Alekseyev

Antworten:

139

Sie könnten eine Rückkehr Integeranstelle einer int, Rückkehr nullauf Parse - Ausfall.

Es ist eine Schande, dass Java keine Möglichkeit bietet, dies zu tun, ohne dass eine Ausnahme intern ausgelöst wird. Sie können die Ausnahme ausblenden (indem Sie sie abfangen und null zurückgeben), aber es kann immer noch ein Leistungsproblem sein, wenn Sie Hunderte analysieren von Tausenden von Bits von vom Benutzer bereitgestellten Daten.

EDIT: Code für eine solche Methode:

public static Integer tryParse(String text) {
  try {
    return Integer.parseInt(text);
  } catch (NumberFormatException e) {
    return null;
  }
}

Beachten Sie, dass ich mir nicht sicher bin, was dies tun wird, wenn textes null ist. Sie sollten Folgendes berücksichtigen: Wenn es sich um einen Fehler handelt (dh Ihr Code kann einen ungültigen Wert übergeben, aber niemals null übergeben), ist das Auslösen einer Ausnahme angemessen. Wenn es keinen Fehler darstellt, sollten Sie wahrscheinlich wie bei jedem anderen ungültigen Wert einfach null zurückgeben.

Ursprünglich verwendete diese Antwort den new Integer(String)Konstruktor; es verwendet jetzt Integer.parseIntund eine Boxoperation; Auf diese Weise werden kleine Werte in zwischengespeicherte IntegerObjekte gepackt , was sie in diesen Situationen effizienter macht.

Jon Skeet
quelle
1
Wie hilft das? Die Aufrufstelle benötigt: <b> temp = tryParse (...); if (temp! = Null) {target = temp; } else {Wiederherstellungsaktion ausführen}; </ b> mit einer wahrscheinlichen Auslöseausnahme im Wiederherstellungsteil. In der ursprünglichen Formulierung erfordert die Aufrufstelle <b> try target = (...). ParseInt; catch (...) {Wiederherstellungsaktion ausführen} </ b> mit einer geringfügigen Auslöseausnahme bei der Wiederherstellung, die durch einfaches Entfernen der catch-Klausel implementiert wird. Wie erleichtert die vorgeschlagene Lösung das Verständnis (es hat einen Zaubertrick) oder reduziert die Codemenge in irgendeiner Weise?
Ira Baxter
14
Es ist im Allgemeinen sauberer, Code auf nullReferenzen zu überprüfen, als Ausnahmen regelmäßig zu behandeln.
Adam Maras
Es ist noch sauberer zu vermeiden, Nullen als Werte zu übergeben, sondern irgendwie darauf hinzuweisen, dass ein Fehler aufgetreten ist. Ausnahmen sollten nicht für die Flusskontrolle verwendet werden.
Esko
2
@ Steve Kuo: Warum? Wo ist der Vorteil? Beide erstellen jedes Mal eine neue Ganzzahl? Wenn überhaupt, bin ich versucht, Integer.parseInt zu verwenden und Autoboxing dafür zu sorgen, um den Cache für kleine Werte zu nutzen.
Jon Skeet
1
@Vlasec Und nicht nur optionale, sondern auch spezielle Versionen für Grundelemente wie OptionalInt.
Joshua Taylor
36

Welches Verhalten erwarten Sie, wenn es keine Zahl ist?

Wenn Sie beispielsweise häufig einen Standardwert verwenden müssen, wenn die Eingabe keine Zahl ist, kann eine solche Methode hilfreich sein:

public static int parseWithDefault(String number, int defaultVal) {
  try {
    return Integer.parseInt(number);
  } catch (NumberFormatException e) {
    return defaultVal;
  }
}

Ähnliche Methoden können für ein anderes Standardverhalten geschrieben werden, wenn die Eingabe nicht analysiert werden kann.

Joachim Sauer
quelle
29

In einigen Fällen sollten Sie Analysefehler als ausfallsichere Situationen behandeln, in anderen Fällen, z. B. bei der Anwendungskonfiguration, bevorzuge ich die Behandlung fehlender Eingaben mit Standardwerten mithilfe von Apache Commons Lang 3 NumberUtils .

int port = NumberUtils.toInt(properties.getProperty("port"), 8080);
Bryan W. Wagner
quelle
Meistens verwenden Sie Apache Commons aus anderen Gründen (wie StringUtils) bereits in Ihrem Projekt. Dies ist praktisch.
Ratata Tata
16

Um die Behandlung von Ausnahmen zu vermeiden, verwenden Sie einen regulären Ausdruck, um sicherzustellen, dass Sie zuerst alle Ziffern haben:

//Checking for Regular expression that matches digits
if(value.matches("\\d+")) {
     Integer.parseInt(value);
}
Daddyboy
quelle
Vielen Dank für Ihre Antwort. Ich habe die meisten Antworten auf dieser Seite gelesen und persönlich die Try / Catch-Lösung geschrieben. Hier ist jedoch mein, wenn auch kleines Problem mit dieser Lösung. Die meisten IDEs drosseln bei der Analyse des Codeflusses, wenn Sie einen Versuch / Fang in einer Schleife haben. Deshalb war eine Lösung ohne Try / Catch das, was ich brauchte.
Sieger n.
4
Achtung. Die Regex mit entspricht einer Ganzzahl, die mit 0 beginnt, und löst dann eine NumberFormatException aus. Versuchen Sie dies ^ (?: [1-9] \ d * | 0) $ von stackoverflow.com/questions/12018479/…
Goose
4
Diese spezielle Regex würde keine negativen Zahlen verarbeiten.
Brad Cupit
6
Auch dies deckt keine Nummernkreise ab, die außerhalb ganzzahliger Grenzen liegen
Mohammad Yahia,
10

Es gibt Ints.tryParse()in Guave . Es wird keine Ausnahme für nicht numerische Zeichenfolgen ausgelöst, jedoch keine Ausnahme für Nullzeichenfolgen.

husayt
quelle
4

Nach dem Lesen der Antworten auf die Frage denke ich, dass das Einkapseln oder Umschließen der parseInt-Methode nicht erforderlich ist, vielleicht sogar keine gute Idee.

Sie könnten 'null' zurückgeben, wie Jon vorgeschlagen hat, aber das ersetzt mehr oder weniger ein try / catch-Konstrukt durch eine Null-Prüfung. Es gibt nur einen kleinen Unterschied im Verhalten, wenn Sie die Fehlerbehandlung "vergessen": Wenn Sie die Ausnahme nicht abfangen, gibt es keine Zuweisung und die Variable auf der linken Seite behält den alten Wert bei. Wenn Sie nicht auf Null testen, werden Sie wahrscheinlich von der JVM (NPE) getroffen.

Der Vorschlag von yawn sieht für mich eleganter aus, weil ich es nicht mag, null zurückzugeben, um einige Fehler oder außergewöhnliche Zustände anzuzeigen. Jetzt müssen Sie die referenzielle Gleichheit mit einem vordefinierten Objekt überprüfen, das auf ein Problem hinweist. Aber wie andere argumentieren, wenn Sie erneut die Überprüfung vergessen und ein String nicht analysierbar ist, setzt das Programm das umschlossene Int in Ihrem 'ERROR'- oder' NULL'-Objekt fort.

Die Lösung von Nikolay ist noch objektorientierter und funktioniert auch mit parseXXX-Methoden aus anderen Wrapper-Klassen. Am Ende hat er jedoch nur die NumberFormatException durch eine OperationNotSupported-Ausnahme ersetzt. Auch hier benötigen Sie einen Versuch / Fang, um nicht analysierbare Eingaben zu verarbeiten.

Daher ist es meine Schlussfolgerung, die einfache parseInt-Methode nicht zu kapseln. Ich würde nur einkapseln, wenn ich auch eine (anwendungsabhängige) Fehlerbehandlung hinzufügen könnte.

Andreas Dolk
quelle
4

Vielleicht können Sie so etwas verwenden:

public class Test {
public interface Option<T> {
    T get();

    T getOrElse(T def);

    boolean hasValue();
}

final static class Some<T> implements Option<T> {

    private final T value;

    public Some(T value) {
        this.value = value;
    }

    @Override
    public T get() {
        return value;
    }

    @Override
    public T getOrElse(T def) {
        return value;
    }

    @Override
    public boolean hasValue() {
        return true;
    }
}

final static class None<T> implements Option<T> {

    @Override
    public T get() {
        throw new UnsupportedOperationException();
    }

    @Override
    public T getOrElse(T def) {
        return def;
    }

    @Override
    public boolean hasValue() {
        return false;
    }

}

public static Option<Integer> parseInt(String s) {
    Option<Integer> result = new None<Integer>();
    try {
        Integer value = Integer.parseInt(s);
        result = new Some<Integer>(value);
    } catch (NumberFormatException e) {
    }
    return result;
}

}
Nikolay Ivanov
quelle
Ich mag Ihre Lösung mit dem Vielleicht-Muster. Sehr haskelly;)
rodrigoelp
1
Diese Lösung ist jetzt veraltet, da es java.util.Optional seit Java 8 gibt :)
Vlasec
2

Sie können das gewünschte C ++ - Verhalten auch ganz einfach replizieren

public static boolean parseInt(String str, int[] byRef) {
    if(byRef==null) return false;
    try {
       byRef[0] = Integer.parseInt(prop);
       return true;
    } catch (NumberFormatException ex) {
       return false;
    }
}

Sie würden die Methode wie folgt verwenden:

int[] byRef = new int[1];
boolean result = parseInt("123",byRef);

Danach ist die Variable resultwahr, wenn alles in Ordnung ist und byRef[0]den analysierten Wert enthält.

Persönlich würde ich mich an die Ausnahme halten.


quelle
2

Die Antwort von Jon Skeet ist in Ordnung, aber ich gebe kein nullInteger-Objekt zurück. Ich finde das verwirrend zu benutzen. Seit Java 8 gibt es (meiner Meinung nach) eine bessere Option OptionalInt:

public static OptionalInt tryParse(String value) {
 try {
     return OptionalInt.of(Integer.parseInt(value));
  } catch (NumberFormatException e) {
     return OptionalInt.empty();
  }
}

Dies macht deutlich, dass Sie den Fall behandeln müssen, in dem kein Wert verfügbar ist. Ich würde es vorziehen, wenn diese Art von Funktion in Zukunft zur Java-Bibliothek hinzugefügt würde, aber ich weiß nicht, ob dies jemals passieren wird.

Marc
quelle
2

Wenn Sie Java 8 oder höher verwenden, können Sie eine Bibliothek verwenden, die ich gerade veröffentlicht habe: https://github.com/robtimus/try-parse . Es unterstützt int, long und boolean, ohne dass Ausnahmen abgefangen werden müssen. Im Gegensatz zu Ints.tryParse von Guava wird OptionalInt / OptionalLong / Optional zurückgegeben, ähnlich wie in https://stackoverflow.com/a/38451745/1180351, jedoch effizienter.

Rob Spoor
quelle
1

Mein Java ist etwas rostig, aber lassen Sie mich sehen, ob ich Sie in die richtige Richtung weisen kann:

public class Converter {

    public static Integer parseInt(String str) {
        Integer n = null;

        try {
            n = new Integer(Integer.tryParse(str));
        } catch (NumberFormatException ex) {
            // leave n null, the string is invalid
        }

        return n;
    }

}

Wenn Ihr Rückgabewert ist null, haben Sie einen schlechten Wert. Ansonsten haben Sie eine gültige Integer.

Adam Maras
quelle
Das OP möchte das Konvertierungsergebnis (als Referenz) sowie einen Hinweis darauf, dass die Konvertierung erfolgreich war (oder nicht).
Gähnen
1
@yawn: Und eine Nullreferenz gibt genau diesen Hinweis.
Jon Skeet
@ John Skeet: Richtig, aber ich habe seine Absicht anders gelesen. Er schrieb so etwas wie die Verwendung eines Zwischenobjekts, um zwischen Erfolg / Misserfolg + Wert zu unterscheiden. Aus einem C ++ - Hintergrund stammend, dachte ich, wenn er null (anstelle eines Objekts) verwenden wollte, hätte er die Frage überhaupt nicht gestellt.
Gähnen
Es gibt einen großen Unterschied zwischen "Wert" und "Objekt". Eine Nullreferenz ist ein sauberer Wert, aber kein Objekt.
Jon Skeet
1. Integer.tryParseIn der Standard-Java- IntegerKlasse gibt es keine . 2. Dies new Integerist nicht erforderlich (und wird dagegen empfohlen), da Java das Boxen und Entpacken automatisch durchführt. Ihr Java ist nicht nur ein bisschen rostig, es ist auch sehr rostig.
ADTC
1

Was ist mit dem Verzweigen der parseInt- Methode?

Es ist einfach, einfach kopieren und einfügen den Inhalt in ein neues Dienstprogramm , dass die Rendite Integeroder Optional<Integer>und mit Renditen wirft ersetzen. Es scheint, dass es keine Ausnahmen im zugrunde liegenden Code gibt, aber besser überprüfen .

Durch Überspringen der gesamten Ausnahmebehandlung können Sie bei ungültigen Eingaben Zeit sparen. Und die Methode gibt es seit JDK 1.0, sodass Sie wahrscheinlich nicht viel tun müssen, um sie auf dem neuesten Stand zu halten.

Vlasec
quelle
0

Ich würde vorschlagen, dass Sie eine Methode wie in Betracht ziehen

 IntegerUtilities.isValidInteger(String s)

die Sie dann nach Belieben implementieren. Wenn Sie möchten, dass das Ergebnis zurückgeführt wird - möglicherweise weil Sie Integer.parseInt () trotzdem verwenden -, können Sie den Array-Trick verwenden.

 IntegerUtilities.isValidInteger(String s, int[] result)

Hier setzen Sie das Ergebnis [0] auf den im Prozess gefundenen ganzzahligen Wert.

Thorbjørn Ravn Andersen
quelle
0

Dies ähnelt etwas der Lösung von Nikolay:

 private static class Box<T> {
  T me;
  public Box() {}
  public T get() { return me; }
  public void set(T fromParse) { me = fromParse; }
 }

 private interface Parser<T> {
  public void setExclusion(String regex);
  public boolean isExcluded(String s);
  public T parse(String s);
 }

 public static <T> boolean parser(Box<T> ref, Parser<T> p, String toParse) {
  if (!p.isExcluded(toParse)) {
   ref.set(p.parse(toParse));
   return true;
  } else return false;
 }

 public static void main(String args[]) {
  Box<Integer> a = new Box<Integer>();
  Parser<Integer> intParser = new Parser<Integer>() {
   String myExclusion;
   public void setExclusion(String regex) {
    myExclusion = regex;
   }
   public boolean isExcluded(String s) {
    return s.matches(myExclusion);
   }
   public Integer parse(String s) {
    return new Integer(s);
   }
  };
  intParser.setExclusion("\\D+");
  if (parser(a,intParser,"123")) System.out.println(a.get());
  if (!parser(a,intParser,"abc")) System.out.println("didn't parse "+a.get());
 }

Die Hauptmethode demonstriert den Code. Eine andere Möglichkeit, die Parser-Schnittstelle zu implementieren, besteht offensichtlich darin, einfach "\ D +" aus der Konstruktion zu setzen und die Methoden nichts tun zu lassen.

Carl
quelle
0

Sie könnten Ihre eigenen rollen, aber es ist genauso einfach, die StringUtils.isNumeric() Methode von commons lang zu verwenden . Es verwendet Character.isDigit () , um jedes Zeichen in der Zeichenfolge zu durchlaufen.

James Bassett
quelle
Dann würde es nicht funktionieren, wenn die Ziffer eine zu große Zahl enthält. Integer.parseInt löst eine Ausnahme für Zahlen aus, die größer als Integer.MAX_VALUE sind (dies gilt natürlich auch für die negative Seite).
Searles
0

Die Art und Weise, wie ich mit diesem Problem umgehe, ist rekursiv. Zum Beispiel beim Lesen von Daten von der Konsole:

Java.util.Scanner keyboard = new Java.util.Scanner(System.in);

public int GetMyInt(){
    int ret;
    System.out.print("Give me an Int: ");
    try{
        ret = Integer.parseInt(keyboard.NextLine());

    }
    catch(Exception e){
        System.out.println("\nThere was an error try again.\n");
        ret = GetMyInt();
    }
    return ret;
}
Boboman
quelle
0

Um eine Ausnahme zu vermeiden, können Sie die Java- Format.parseObjectMethode verwenden. Der folgende Code ist im Grunde eine vereinfachte Version der IntegerValidator- Klasse von Apache Common .

public static boolean tryParse(String s, int[] result)
{
    NumberFormat format = NumberFormat.getIntegerInstance();
    ParsePosition position = new ParsePosition(0);
    Object parsedValue = format.parseObject(s, position);

    if (position.getErrorIndex() > -1)
    {
        return false;
    }

    if (position.getIndex() < s.length())
    {
        return false;
    }

    result[0] = ((Long) parsedValue).intValue();
    return true;
}

Sie können je nach Wunsch entweder AtomicIntegerden int[]Array-Trick oder den Array-Trick verwenden.

Hier ist mein Test, der es verwendet -

int[] i = new int[1];
Assert.assertTrue(IntUtils.tryParse("123", i));
Assert.assertEquals(123, i[0]);
Josh Unger
quelle
0

Ich hatte auch das gleiche Problem. Dies ist eine Methode, die ich geschrieben habe, um den Benutzer nach einer Eingabe zu fragen und die Eingabe nur zu akzeptieren, wenn es sich um eine Ganzzahl handelt. Bitte beachten Sie, dass ich ein Anfänger bin. Wenn der Code nicht wie erwartet funktioniert, beschuldigen Sie meine Unerfahrenheit!

private int numberValue(String value, boolean val) throws IOException {
    //prints the value passed by the code implementer
    System.out.println(value);
    //returns 0 is val is passed as false
    Object num = 0;
    while (val) {
        num = br.readLine();
        try {
            Integer numVal = Integer.parseInt((String) num);
            if (numVal instanceof Integer) {
                val = false;
                num = numVal;
            }
        } catch (Exception e) {
            System.out.println("Error. Please input a valid number :-");
        }
    }
    return ((Integer) num).intValue();
}
Abhinav Mathur
quelle
1
Verwenden Sie nicht System.out.println (ist eine schlechte Praxis). Das Problem bei der Verwendung ist, dass Ihr Programm wartet, bis der Druckvorgang abgeschlossen ist. Der bessere Ansatz ist die Verwendung eines Protokollierungsframeworks.
Omar Hrynkiewicz
0

Dies ist eine Antwort auf die Frage 8391979 "Hat Java eine int.tryparse, die keine Ausnahme für fehlerhafte Daten auslöst? [Duplikat]", die geschlossen und mit dieser Frage verknüpft ist.

Edit 2016 08 17: ltrimZeroes-Methoden hinzugefügt und in tryParse () aufgerufen. Ohne führende Nullen in numberString können falsche Ergebnisse erzielt werden (siehe Kommentare im Code). Es gibt jetzt auch die öffentliche statische String ltrimZeroes-Methode (String numberString), die für positive und negative "Zahlen" funktioniert (END Edit).

Unten finden Sie eine rudimentäre Wrapper (Boxing) -Klasse für int mit einer hochgeschwindigkeitsoptimierten tryParse () -Methode (ähnlich wie in C #), die den String selbst analysiert und etwas schneller als Integer.parseInt (String s) aus Java ist:

public class IntBoxSimple {
    // IntBoxSimple - Rudimentary class to implement a C#-like tryParse() method for int
    // A full blown IntBox class implementation can be found in my Github project
    // Copyright (c) 2016, Peter Sulzer, Fürth
    // Program is published under the GNU General Public License (GPL) Version 1 or newer

    protected int _n; // this "boxes" the int value

    // BEGIN The following statements are only executed at the
    // first instantiation of an IntBox (i. e. only once) or
    // already compiled into the code at compile time:
    public static final int MAX_INT_LEN =
            String.valueOf(Integer.MAX_VALUE).length();
    public static final int MIN_INT_LEN =
            String.valueOf(Integer.MIN_VALUE).length();
    public static final int MAX_INT_LASTDEC =
            Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(1));
    public static final int MAX_INT_FIRSTDIGIT =
            Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(0, 1));
    public static final int MIN_INT_LASTDEC =
            -Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(2));
    public static final int MIN_INT_FIRSTDIGIT =
            Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(1,2));
    // END The following statements...

    // ltrimZeroes() methods added 2016 08 16 (are required by tryParse() methods)
    public static String ltrimZeroes(String s) {
        if (s.charAt(0) == '-')
            return ltrimZeroesNegative(s);
        else
            return ltrimZeroesPositive(s);
    }
    protected static String ltrimZeroesNegative(String s) {
        int i=1;
        for ( ; s.charAt(i) == '0'; i++);
        return ("-"+s.substring(i));
    }
    protected static String ltrimZeroesPositive(String s) {
        int i=0;
        for ( ; s.charAt(i) == '0'; i++);
        return (s.substring(i));
    }

    public static boolean tryParse(String s,IntBoxSimple intBox) {
        if (intBox == null)
            // intBoxSimple=new IntBoxSimple(); // This doesn't work, as
            // intBoxSimple itself is passed by value and cannot changed
            // for the caller. I. e. "out"-arguments of C# cannot be simulated in Java.
            return false; // so we simply return false
        s=s.trim(); // leading and trailing whitespace is allowed for String s
        int len=s.length();
        int rslt=0, d, dfirst=0, i, j;
        char c=s.charAt(0);
        if (c == '-') {
            if (len > MIN_INT_LEN) { // corrected (added) 2016 08 17
                s = ltrimZeroesNegative(s);
                len = s.length();
            }
            if (len >= MIN_INT_LEN) {
                c = s.charAt(1);
                if (!Character.isDigit(c))
                    return false;
                dfirst = c-'0';
                if (len > MIN_INT_LEN || dfirst > MIN_INT_FIRSTDIGIT)
                    return false;
            }
            for (i = len - 1, j = 1; i >= 2; --i, j *= 10) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt -= (c-'0')*j;
            }
            if (len < MIN_INT_LEN) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt -= (c-'0')*j;
            } else {
                if (dfirst >= MIN_INT_FIRSTDIGIT && rslt < MIN_INT_LASTDEC)
                    return false;
                rslt -= dfirst * j;
            }
        } else {
            if (len > MAX_INT_LEN) { // corrected (added) 2016 08 16
                s = ltrimZeroesPositive(s);
                len=s.length();
            }
            if (len >= MAX_INT_LEN) {
                c = s.charAt(0);
                if (!Character.isDigit(c))
                    return false;
                dfirst = c-'0';
                if (len > MAX_INT_LEN || dfirst > MAX_INT_FIRSTDIGIT)
                    return false;
            }
            for (i = len - 1, j = 1; i >= 1; --i, j *= 10) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt += (c-'0')*j;
            }
            if (len < MAX_INT_LEN) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt += (c-'0')*j;
            }
            if (dfirst >= MAX_INT_FIRSTDIGIT && rslt > MAX_INT_LASTDEC)
                return false;
            rslt += dfirst*j;
        }
        intBox._n=rslt;
        return true;
    }

    // Get the value stored in an IntBoxSimple:
    public int get_n() {
        return _n;
    }
    public int v() { // alternative shorter version, v for "value"
        return _n;
    }
    // Make objects of IntBoxSimple (needed as constructors are not public):
    public static IntBoxSimple makeIntBoxSimple() {
        return new IntBoxSimple();
    }
    public static IntBoxSimple makeIntBoxSimple(int integerNumber) {
        return new IntBoxSimple(integerNumber);
    }

    // constructors are not public(!=:
    protected IntBoxSimple() {} {
        _n=0; // default value an IntBoxSimple holds
    }
    protected IntBoxSimple(int integerNumber) {
        _n=integerNumber;
    }
}

Test- / Beispielprogramm für die Klasse IntBoxSimple:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class IntBoxSimpleTest {
    public static void main (String args[]) {
        IntBoxSimple ibs = IntBoxSimple.makeIntBoxSimple();
        String in = null;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        do {
            System.out.printf(
                    "Enter an integer number in the range %d to %d:%n",
                        Integer.MIN_VALUE, Integer.MAX_VALUE);
            try { in = br.readLine(); } catch (IOException ex) {}
        } while(! IntBoxSimple.tryParse(in, ibs));
        System.out.printf("The number you have entered was: %d%n", ibs.v());
    }
}
Peter Sulzer
quelle
0

Versuchen Sie es mit einem regulären Ausdruck und einem Standardparameterargument

public static int parseIntWithDefault(String str, int defaultInt) {
    return str.matches("-?\\d+") ? Integer.parseInt(str) : defaultInt;
}


int testId = parseIntWithDefault("1001", 0);
System.out.print(testId); // 1001

int testId = parseIntWithDefault("test1001", 0);
System.out.print(testId); // 1001

int testId = parseIntWithDefault("-1001", 0);
System.out.print(testId); // -1001

int testId = parseIntWithDefault("test", 0);
System.out.print(testId); // 0

Wenn Sie apache.commons.lang3 verwenden, verwenden Sie NumberUtils :

int testId = NumberUtils.toInt("test", 0);
System.out.print(testId); // 0
Krunal
quelle
0

Ich möchte einen weiteren Vorschlag einbringen, der funktioniert, wenn speziell Ganzzahlen angefordert werden: Verwenden Sie einfach long und Long.MIN_VALUE für Fehlerfälle. Dies ähnelt dem Ansatz, der für Zeichen in Reader verwendet wird, wobei Reader.read () eine Ganzzahl im Bereich eines Zeichens oder -1 zurückgibt, wenn der Leser leer ist.

Für Float und Double kann NaN auf ähnliche Weise verwendet werden.

public static long parseInteger(String s) {
    try {
        return Integer.parseInt(s);
    } catch (NumberFormatException e) {
        return Long.MIN_VALUE;
    }
}


// ...
long l = parseInteger("ABC");
if (l == Long.MIN_VALUE) {
    // ... error
} else {
    int i = (int) l;
}
Searles
quelle
0

In Anbetracht der vorhandenen Antworten habe ich den Quellcode für Integer.parseIntmeine Arbeit und meine Lösung kopiert und erweitert

  • verwendet keinen potenziell langsamen Try-Catch (im Gegensatz zu Lang 3 NumberUtils ),
  • verwendet keine regulären Ausdrücke, die nicht zu große Zahlen abfangen können,
  • vermeidet Boxen (im Gegensatz zu Guaven Ints.tryParse()),
  • keine Zuweisungen erfordert ( im Gegensatz zu int[], Box, OptionalInt),
  • akzeptiert etwas CharSequenceoder einen Teil davon anstelle eines Ganzen String,
  • kann jeden Radix verwenden, der Integer.parseIntkann, dh [2,36],
  • hängt nicht von Bibliotheken ab.

Der einzige Nachteil ist, dass es keinen Unterschied zwischen toIntOfDefault("-1", -1)und gibt toIntOrDefault("oops", -1).

public static int toIntOrDefault(CharSequence s, int def) {
    return toIntOrDefault0(s, 0, s.length(), 10, def);
}
public static int toIntOrDefault(CharSequence s, int def, int radix) {
    radixCheck(radix);
    return toIntOrDefault0(s, 0, s.length(), radix, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int def) {
    boundsCheck(start, endExclusive, s.length());
    return toIntOrDefault0(s, start, endExclusive, 10, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int radix, int def) {
    radixCheck(radix);
    boundsCheck(start, endExclusive, s.length());
    return toIntOrDefault0(s, start, endExclusive, radix, def);
}
private static int toIntOrDefault0(CharSequence s, int start, int endExclusive, int radix, int def) {
    if (start == endExclusive) return def; // empty

    boolean negative = false;
    int limit = -Integer.MAX_VALUE;

    char firstChar = s.charAt(start);
    if (firstChar < '0') { // Possible leading "+" or "-"
        if (firstChar == '-') {
            negative = true;
            limit = Integer.MIN_VALUE;
        } else if (firstChar != '+') {
            return def;
        }

        start++;
        // Cannot have lone "+" or "-"
        if (start == endExclusive) return def;
    }
    int multmin = limit / radix;
    int result = 0;
    while (start < endExclusive) {
        // Accumulating negatively avoids surprises near MAX_VALUE
        int digit = Character.digit(s.charAt(start++), radix);
        if (digit < 0 || result < multmin) return def;
        result *= radix;
        if (result < limit + digit) return def;
        result -= digit;
    }
    return negative ? result : -result;
}
private static void radixCheck(int radix) {
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
        throw new NumberFormatException(
                "radix=" + radix + " ∉ [" +  Character.MIN_RADIX + "," + Character.MAX_RADIX + "]");
}
private static void boundsCheck(int start, int endExclusive, int len) {
    if (start < 0 || start > len || start > endExclusive)
        throw new IndexOutOfBoundsException("start=" + start + " ∉ [0, min(" + len + ", " + endExclusive + ")]");
    if (endExclusive > len)
        throw new IndexOutOfBoundsException("endExclusive=" + endExclusive + " > s.length=" + len);
}
Miha_x64
quelle
-1

Sie können ein Null-Objekt wie folgt verwenden:

public class Convert {

    @SuppressWarnings({"UnnecessaryBoxing"})
    public static final Integer NULL = new Integer(0);

    public static Integer convert(String integer) {

        try {
            return Integer.valueOf(integer);
        } catch (NumberFormatException e) {
            return NULL;
        }

    }

    public static void main(String[] args) {

        Integer a = convert("123");
        System.out.println("a.equals(123) = " + a.equals(123));
        System.out.println("a == NULL " + (a == NULL));

        Integer b = convert("onetwothree");
        System.out.println("b.equals(123) = " + b.equals(123));
        System.out.println("b == NULL " + (b == NULL));

        Integer c = convert("0");
        System.out.println("equals(0) = " + c.equals(0));
        System.out.println("c == NULL " + (c == NULL));

    }

}

Das Ergebnis von main in diesem Beispiel ist:

a.equals(123) = true
a == NULL false
b.equals(123) = false
b == NULL true
c.equals(0) = true
c == NULL false

Auf diese Weise können Sie immer auf fehlgeschlagene Konvertierung testen und trotzdem mit den Ergebnissen als Integer-Instanzen arbeiten. Möglicherweise möchten Sie auch die Zahl anpassen, die NULL darstellt (≠ 0).

gähnen
quelle
Was ist, wenn 'String integer' das String-Literal "0" ist? Sie werden nie erfahren, ob eine ungültige Eingabe vorliegt.
Bart Kiers
Ich denke, das hängt davon ab, ob der Operator == für zwei Ganzzahlen Werte oder Referenzen vergleicht. Wenn Werte verglichen werden, liegt das Problem vor. Wenn es Referenzen vergleicht, würde es auf eine Weise funktionieren, die meiner Antwort entspricht.
Adam Maras
Warum das Downvote? Meine Antwort ist richtig und bietet den Vorteil (gegenüber null), dass Sie immer mit einer gültigen Instanz von Integer (anstelle von null) arbeiten, sodass Sie sich nicht mehr mit NPEs befassen müssen.
Gähnen
Es ist jedoch nützlich, null von einer reellen Ganzzahl zu unterscheiden . Sie sollten das Ergebnis auf Nichtigkeit testen, um festzustellen, ob die Analyse erfolgreich war oder nicht. Das Verstecken hinter und ansonsten verwendbaren Objekt ist ein Rezept für Probleme, IMO.
Jon Skeet
Weitere Abstimmungen - interessant! Da ich neu bei SO bin und alle, könnte mir einer der Wähler das Warum erklären?
Gähnen
-1

Sie sollten keine Ausnahmen verwenden, um Ihre Werte zu überprüfen .

Für einzelne Zeichen gibt es eine einfache Lösung:

Character.isDigit()

Für längere Werte ist es besser, einige Utils zu verwenden. Von Apache bereitgestellte NumberUtils würden hier perfekt funktionieren:

NumberUtils.isNumber()

Bitte überprüfen Sie https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html

Bogdan Aksonenko
quelle
«Überprüft, ob der String eine gültige Java-Nummer ist. Gültige Zahlen sind Hexadezimalzahlen, die mit dem 0x-Qualifikationsmerkmal gekennzeichnet sind, wissenschaftliche Notation und Zahlen, die mit einem Typqualifikationsmerkmal (z. B. 123L) gekennzeichnet sind. » Damit kann man nicht analysieren Integer.parseInt.
Miha_x64