web-dev-qa-db-fra.com

Comment savoir quelle variable est le coupable dans le bloc try?

Dans un certain bloc try, j'ai deux variables String qui pourraient causer NumberFormatException quand je sais utiliser Integer.parseInt(string1) etInteger.parseInt(string2). La question est, si je catch une exception, comment savoir quelle chaîne est le fauteur de troubles? J'ai besoin du nom de la variable du fauteur de troubles.

Voici un exemple de code:

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();
        }
        }
    }

Et la méthode e.printStackTrace() ne me dit pas le nom de la variable; il me dit simplement le contenu du fauteur de troubles.

Java.lang.NumberFormatException: pour la chaîne d'entrée: "fdsa" à Java.lang.NumberFormatException.forInputString (NumberFormatException.Java:65) à Java.lang.Integer.parseInt (Integer.Java:580) à Java.lang.Integer.parseInt (Integer.Java:615) à test.main (test.Java:9) à Sun.reflect.NativeMethodAccessorImpl.invoke0 (Méthode native) à Sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.Java:62) à Sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.Java:43) à Java.lang.reflect.Method.invoke (Method.Java:498) à com.intellij.rt.execution.application.AppMain.main (AppMain.Java:147)

Processus terminé avec le code de sortie 0

La raison pour laquelle j'ai besoin de connaître le nom de la variable est que je dois informer l'utilisateur de ce qui se passe. Par exemple, indiquez à l'utilisateur que chaîne1 est erronée à l'aide de

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

Dans mes exigences, l'utilisateur doit entrer

fd=(fileName,maxLength,minLength)

ensuite, j'analyserai la chaîne d'entrée et créerai des réponses. Je voudrais donc vérifier si les variables maxLength et minLength jetteront NumberFormatException. Dans ce cas, si minLength a un problème, je dois informer l'utilisateur que minLength est incorrect.

40
guo

Vous rencontrez un problème XY .

Vous ne voulez pas lire le nom de la variable réelle. Vous voulez pouvoir valider les entrées et donner des messages d'erreur raisonnables à votre utilisateur.

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

Ne pas lancer les exceptions directement mais les collecter vous permet d'informer l'utilisateur de toutes les entrées non valides en même temps (peut-être mettre en surbrillance les champs associés en rouge) au lieu de les laisser corriger une entrée, essayer de soumettre à nouveau, puis de voir qu'une autre entrée est également faux.

Au lieu de Strings, vous pouvez utiliser votre propre structure de données contenant des informations sur le champ concerné, etc., mais cela sort rapidement de la portée. Le Gist principal est le suivant: utilisez deux blocs try-catch et vous pourrez différencier les champs erronés.

Si plusieurs entrées sont impliquées, vous pouvez reformuler ceci dans une boucle.

69
Polygnome

Utilisez 2 blocs try, catch séparés pour analyser deux entrées pour chaque variable. Générez ensuite le message de vérification d'intégrité à l'intérieur de chaque bloc catch.

        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
Chand Priyankara

J'aimerais écrire ma propre méthode parseInt:

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

Comme je le sais, nous ne pouvons pas lire un nom de variable par réflexion, je passe donc plutôt un littéral String:

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

Je vais laisser la réponse d'origine et fournir une version qui a discuté dans les commentaires. Mais pour le moment, je ne comprends pas pourquoi un fournisseur est excessif.

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

Son appel ressemble à

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

Avant de réaliser l'opération, vous pouvez écrire une simple fonction isInteger () pouvant vous renvoyer un booléen. Une bonne implémentation peut être trouvée sur ce fil. Cela utilise la radix de la valeur et itère s’il s’agit d’un int et s’avère plutôt pratique . Déterminer si une chaîne est un entier en Java l'argument

4
Ramachandran.A.G

Il suffit d'utiliser un autre essai de capture pour l'autre déclaration

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

Je suis surpris que personne n'ait proposé quelque chose comme ça:

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();
    }
    }
}

C'est une solution très simple - simpliste, diraient certains - mais elle est également assez claire et robuste.

Si j'ai bien compris, l'objectif de cette question n'était pas de fournir un meilleur moyen de convertir des chaînes en entiers (même si cela peut effectivement exister), mais plutôt de trouver un moyen de ne pas dire que quoi est allé faux dans un long bloc try, mais aussi (où} _ ça s'est mal passé. Si le but est d'afficher un message d'erreur significatif à l'utilisateur (suggérant idéalement quoi faire plutôt que de se plaindre que quelque chose ne va pas), alors simplement imprimer une trace de pile n'est pas suffisant, bien sûr, et essayer d'attraper chaque ligne de code n'est pas une option attrayante non plus.

2
Branko Radovanović

Vous pouvez créer une méthode avec un test/catch qui renvoie la valeur que vous affectez ou affiche sur la console qu'il y a un problème. Ainsi, vous pouvez gérer autant de variables que vous le souhaitez avec un test/catch tout en suivant le nom de tous les variables qui causent un problème.

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

Vous devez éviter d'attraper Runtime exceptions et utiliser un autre mécanisme d'identification des erreurs. Dans votre cas, vous pouvez utiliser Matcher et votre problème pourrait être écrit comme suit:

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
            }
            ...
    }
}

Ou vous pouvez simplement écrire

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

C'est assez simpliste, mais voici ma solution ..

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