web-dev-qa-db-de.com

Woher weiß man, welche Variable der Täter im try-Block ist?

In einem bestimmten try-Block habe ich zwei String-Variablen, die NumberFormatException verursachen könnten, wenn ich Integer.parseInt(string1) undInteger.parseInt(string2) benutze. Die Frage ist, wenn ich catch eine Ausnahme bin, woher weiß man, welche Zeichenfolge der Störenfried ist? Ich muss den Variablennamen des Störenherstellers erhalten.

Hier ist ein Beispielcode:

public class test {
    public static void main(String[] args) {
        try {
            String string1 = "fdsa";
            String string2 = "fbbbb";
            Integer.parseInt(string1);
            Integer.parseInt(string2);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        }
    }

Und die Methode e.printStackTrace() sagt mir den Variablennamen nicht; es sagt mir nur den Inhalt des Störers.

Java.lang.NumberFormatException: Für die Eingabezeichenfolge: "fdsa" um Java.lang.NumberFormatException.forInputString (NumberFormatException.Java:65) at Java.lang.Integer.parseInt (Integer.Java:580) um Java.lang.Integer.parseInt (Integer.Java:615) um test.main (test.Java:9) um Sun.reflect.NativeMethodAccessorImpl.invoke0 (native Methode) um Sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.Java:62) beim Sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.Java:43) at Java.lang.reflect.Method.invoke (Method.Java:498) um ​​ com.intellij.rt.execution.application.AppMain.main (AppMain.Java:147)

Vorgang mit Exitcode 0 beendet

Der Grund, aus dem ich den Namen der Variablen wissen muss, ist, dass ich den Benutzer auffordern muss, was los ist. Sagen Sie dem Benutzer beispielsweise, dass string1 falsch ist, indem Sie verwenden

System.out.println(troubleMakerName + "is wrong!")

In meinen Anforderungen sollte der Benutzer eingeben

fd=(fileName,maxLength,minLength)

dann analysiere ich die Eingabezeichenfolge und erstelle einige Antworten. Ich möchte also prüfen, ob maxLength und minLengthNumberFormatException werfen. Wenn minLength etwas nicht stimmt, muss ich den Benutzer auffordern, dass die MinLength falsch ist.

40
guo

Sie haben ein XY-Problem .

Sie möchten nicht den tatsächlichen Variablennamen lesen. Sie möchten in der Lage sein, Eingaben zu überprüfen und Ihrem Benutzer angemessene Fehlermeldungen zu geben.

String fileName, maxLengthInput, minLengthInput;
int maxLength, minLength;

List<String> errors = new ArrayList<>();

try {
    maxLength = Integer.parseInt(maxlengthInput);
} catch (NumberFormatException nfe) {
    errors.add("Invalid input for maximum length, input is not a number");
}

try {
    minLength = Integer.parseInt(minlengthInput);
} catch (NumberFormatException nfe) {
    errors.add("Invalid input for minimum length, input is not a number");
}

// show all error strings to the user

Wenn Sie die Ausnahmen nicht direkt auslösen, sondern sammeln, können Sie den Benutzer auf einmal über alle ungültigen Eingaben informieren (die entsprechenden Felder möglicherweise mit roter Farbe hervorheben), anstatt eine Eingabe zu korrigieren, erneut zu senden und dann eine weitere Eingabe zu sehen ist auch falsch.

Anstelle von Strings können Sie auch Ihre eigene Datenstruktur mit Informationen zum verwandten Feld usw. verwenden, die jedoch schnell außer Reichweite gerät. Das Hauptmerkmal ist: Verwenden Sie zwei Try-Catch-Blöcke, und Sie können unterscheiden, welches Feld fehlerhaft ist.

Wenn mehr Eingänge vorhanden sind, können Sie dies in eine Schleife umwandeln.

69
Polygnome

Verwenden Sie 2 separate try, catch-Blöcke, um zwei Eingänge für jede Variable zu parsen. Dann generieren Sie die Sanitätsprüfungsnachricht in jedem catch-Block.

        String string1 = "fdsa";
        String string2 = "fbbbb";
        try {
            Integer.parseInt(string1);
        } catch (NumberFormatException e) {
            e.printStackTrace();
            **//Please provide a valid integer for string1**
        }
        try {
            Integer.parseInt(string2 );
        } catch (NumberFormatException e) {
            e.printStackTrace();
           **//Please provide a valid integer for string2** 
        }
10

Ich würde gerne eine eigene parseInt Methode schreiben:

public static int parseInt(String s, 
                           Supplier<? extends RuntimeException> supplier) {
    try {
        return Integer.parseInt(s);
    } catch (NumberFormatException e) {
        throw (RuntimeException)supplier.get().initCause(e);
    }
}

Wie ich weiß, können wir einen Variablennamen nicht durch Reflektion lesen. Deshalb übergeben wir stattdessen ein String-Literal:

parseInt(string1, () -> new NumberFormatException("string1"));

Ich werde die Origin-Antwort verlassen und eine Version bereitstellen, die in den Kommentaren besprochen wurde. Aber vorerst bin ich verwirrt, warum ein Lieferant ein Overkill ist.

public static int parseInt(String s, String message) {
    try {
        return Integer.parseInt(s);
    } catch (NumberFormatException e) {
        throw (NumberFormatException)new NumberFormatException(message).initCause(e);
        // throw new IllegalArgumentException(message, e);
    }
}

Ihr Anruf sieht aus wie

parseInt(string1, "string1");
6
Andrew Tobilko

Bevor Sie die Operation ausführen, können Sie eine einfache isInteger () - Funktion schreiben, die einen Booleschen Wert zurückgibt. Eine gute Implementierung kann in diesem Thread gefunden werden. Dies verwendet die Basis des Werts und iteriert, wenn es sich um ein int handelt, und es ist sehr praktisch Bestimmen Sie, ob ein String in Java eine Ganzzahl ist Eine einfache if-Bedingung kann feststellen, in welchem ​​Wert ein Rogue-Wert vorliegt das Argument

4

Verwenden Sie einfach einen anderen try catch für die andere Anweisung

public class test 
{
    public static void main(String[] args) 
    {
        String string1 = "fdsa";
        String string2 = "fbbbb";

        try 
        {
            Integer.parseInt(string1);
        } 
        catch (NumberFormatException e) 
        {
            System.out.println("string1 is the culprit");
            e.printStackTrace();
        }

        try 
        {
            Integer.parseInt(string2);
        } 
        catch (NumberFormatException e) 
        {
            System.out.println("string2 is the culprit");
            e.printStackTrace();
        }
    }
}
3
Black

Ich bin überrascht, dass niemand so etwas vorgeschlagen hat:

public class test {
public static void main(String[] args) {
    String errorContext;

    try {            
        String string1 = "fdsa";
        String string2 = "fbbbb";

        errorContext = "string1";
        Integer.parseInt(string1);

        errorContext = "string2";
        Integer.parseInt(string2);
    } catch (NumberFormatException e) {
        System.out.println(errorContext + " is wrong!")
        e.printStackTrace();
    }
    }
}

Es ist eine sehr einfache Lösung - vereinfachend würde man sagen - aber es ist auch ziemlich klar und robust.

Der Sinn dieser Frage bestand meines Erachtens nicht darin, Zeichenketten in ganze Zahlen zu konvertieren (auch wenn sie tatsächlich existieren), sondern einen Weg zu finden, nicht nur was falsch zu gehen ein langer try Block, aber auch wo es ging schief. Wenn das Ziel des Benutzers darin besteht, dem Benutzer eine aussagekräftige Fehlermeldung anzuzeigen (idealerweise Vorschläge, anstatt etwas zu beanstanden, dass etwas nicht stimmt), reicht es natürlich nicht aus, eine Stapelverfolgung auszudrucken und jede Codezeile auszuprobieren ist auch keine attraktive Option.

2

Sie könnten eine Methode mit einem Try/Catch erstellen, die den von Ihnen zugewiesenen Wert zurückgibt oder an die Konsole druckt, dass ein Problem aufgetreten ist. Auf diese Weise könnten Sie mit einem Try/Catch beliebig viele Variablen aufnehmen, während Sie gleichzeitig den Namen aller aufzeichnen Variablen, die ein Problem verursachen.

public class test {
    public static void main(String[] args) {
        String string1 = returnString("fdsa", "string1");
        String string2 = returnString("fbbbb", "string2");
    }

    private string returnString(String input, String varName) {
        String str = "";
        try {
            str = input;
            Integer.parseInt(str);
        } catch (NumberFormatException e) {
            System.out.println("Error processing " + varName);
        }
        return str;
    }
}
2
Luke

Sie sollten es vermeiden, Runtime exceptions abzufangen und einen anderen Mechanismus zum Erkennen von Fehlern zu verwenden. In Ihrem Fall könnten Sie Matcher verwenden und Ihr Problem könnte folgendermaßen geschrieben werden:

public class test {

    private static final Pattern pattern = Pattern.compile("\\d+");
    public static void main(String[] args) {
            String string1 = "fdsa";
            String string2 = "fbbbb";
            if (pattern.matcher(string1).matches()) {
                Integer.parseInt(string1);
            } else {
                //string1 is not an integer
            }
            ...
    }
}

Oder du könntest einfach schreiben

boolean errorInLineOne = !pattern.matcher(string1).matches();
...
0
Heisenberg

Es ist ziemlich simpel, aber hier ist meine Lösung ..

public class test
{
    public static int tryParseInt(String str) throws Exception
    {
        try
        {
            return Integer.parseInt(str);
        }
        catch(Exception e)
        {
            System.err.println("tryParseInt: couldn't parse '"+str+"'");
            throw e;
        }
    }

    public static void main(String[] args)
    {
        try
        {
            String string1 = "fdsa";
            String string2 = "fbbbb";

            tryParseInt(string1);
            tryParseInt(string2);
        }
        catch (NumberFormatException e)
        {
            e.printStackTrace();
        }
    }
}
0
Khaled.K