2016-02-19 1 views
2

Je rencontre souvent une situation où j'ai besoin d'analyser une valeur numérique (par exemple avec Integer.parseInt ou Double.parseDouble) et j'ai plusieurs valeurs. Le problème est que je me retrouve à devoir dupliquer la gestion des exceptions et ça devient moche. Par exemple, prenez le code suivant:Comment gérer les numéros d'analyse avec le même bloc catch?

double lowVal, mediumVal, highVal; 
String lowString = "1.2", mediumString = "null", highString = "7.9"; 

try { 
    lowVal = parseDouble(lowString); 
} catch (NumberFormatException NaN) { 
    //Don't care, just carry on trying to parse the rest... 
} 

try { 
    mediumVal = parseDouble(mediumString); 
} catch (NumberFormatException NaN) { 
    //Don't care, just carry on trying to parse the rest... 
} 

try { 
    highVal = parseDouble(highString); 
} catch (NumberFormatException NaN) { 
    //Don't care, just carry on trying to parse the rest... 
} 

Y a-t-il un bon modèle pour faire face à cette situation?

Je ne souhaite pas utiliser un seul déclenchement, car je souhaite continuer à analyser le reste des nombres.

Je dois mentionner que dans cet exemple, les valeurs ne sont pas initialisées mais dans le code de programme actuel elles le seraient. L'affectation ne doit avoir lieu que si les valeurs de chaîne sont analysables.

+0

juste utiliser un try-catch pour tous les trois –

+0

Mais je veux que le reste continue à s'exécuter. Si vous essayez de tous les analyser dans le même bloc try, à chaque fois qu'une exception est levée, comment pouvez-vous continuer à analyser le reste? –

+0

Peut-être mettre le try-catch unique dans une boucle avec des drapeaux qui empêchent la dernière exception qui est levée de s'exécuter à nouveau. – StealthSpoder

Répondre

4

extraire juste une méthode:

double lowVal, mediumVal, highVal; 
String lowString = "1.2", mediumString = "null", highString = "7.9"; 

lowVal = parseDouble(lowString); 
mediumVal = parseDouble(mediumString); 
highVal = parseDouble(highString); 

double parseDouble(String s) { 
    try { 
     return Double.parseDouble(s); 
    } catch (NumberFormatException e) { 
     return Double.NAN; 
    } 
} 

ou

Double lowVal; 
Double mediumVal; 
Double highVal; 
String lowString = "1.2", mediumString = "null", highString = "7.9"; 

lowVal = parseDouble(lowString); 
mediumVal = parseDouble(mediumString); 
highVal = parseDouble(highString); 

Double parseDouble(String s) { 
    try { 
     return Double.parseDouble(s); 
    } catch (NumberFormatException e) { 
     return null; 
    } 
} 
+0

Je ne veux pas attribuer la valeur si elle n'est pas valide. –

+0

@SinaMadani la primitive 'double' est par défaut à une valeur de' 0.0', donc elle aura une valeur de toute façon –

+0

La valeur a peut-être déjà été assignée ailleurs dans le code, je l'utilisais juste comme un exemple simple. Je suppose que je pourrais transmettre la valeur actuelle et l'utiliser comme valeur de retour. –

0

Je voudrais juste utiliser un seul try-catch pour toutes vos valeurs.

+1

Lire les commentaires. –

0

Voici une solution en utilisant des drapeaux et une boucle pour éviter que les exceptions ne se reproduise:

double lowVal, mediumVal, highVal; 
    String lowString = "1.2", mediumString = "null", highString = "7.9"; 
    int count = 0; 
    boolean lowFlag = false, medFlag = false, highFlag = false; 
    do{ 
     try { 
      count = 0; 
      count++; 
      if(!lowFlag) 
       lowVal = parseDouble(lowString); 
      count++; 
      if(!medFlag) 
       mediumVal = parseDouble(mediumString); 
      count++; 
      if(!highFlag) 
       highVal = parseDouble(highString); 

      break; 

     } catch (NumberFormatException NaN) { 
      if(count==0) 
       lowFlag = true; 
      else if(count==1) 
       medFlag = true; 
      else if(count==2) 
       highFlag = true; 
     } 
    }while(true); 
+0

ce code est encore plus verbeux cependant! –

+0

Oui mais je crois que cela résout votre problème. – StealthSpoder

+0

Le problème est celui de la verbosité. Cela ne me dérange pas d'avoir des blocs de capture vides mais j'espérais une solution qui réduirait le code, pas l'augmenter. –

1

Dans le docs de Double vous avez la solution à votre problème.

Pour éviter d'appeler cette méthode sur une chaîne non valide et ayant un NumberFormatException être jeté, l'expression régulière ci-dessous peut être utilisée pour sélectionner la chaîne d'entrée

tout envelopper dans votre méthode parseDouble et suivez les instructions

if (Pattern.matches(fpRegex, myString)) 
      Double.valueOf(myString); // Will not throw NumberFormatException 
     else { 
      // Perform suitable alternative action 
     } 

qui de votre question semble être le remplacer par un autre commentaire

//Don't care, just carry on trying to parse the rest... 

Si le lien devient Innactive (ne devrait jamais arriver), c'est le regex

final String Digits  = "(\\p{Digit}+)"; 
final String HexDigits = "(\\p{XDigit}+)"; 
    // an exponent is 'e' or 'E' followed by an optionally 
    // signed decimal integer. 
    final String Exp  = "[eE][+-]?"+Digits; 
    final String fpRegex = 
     ("[\\x00-\\x20]*"+ // Optional leading "whitespace" 
     "[+-]?(" + // Optional sign character 
     "NaN|" +   // "NaN" string 
     "Infinity|" +  // "Infinity" string 

     // A decimal floating-point string representing a finite positive 
     // number without a leading sign has at most five basic pieces: 
     // Digits . Digits ExponentPart FloatTypeSuffix 
     // 
     // Since this method allows integer-only strings as input 
     // in addition to strings of floating-point literals, the 
     // two sub-patterns below are simplifications of the grammar 
     // productions from the Java Language Specification, 2nd 
     // edition, section 3.10.2. 

     // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt 
     "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+ 

     // . Digits ExponentPart_opt FloatTypeSuffix_opt 
     "(\\.("+Digits+")("+Exp+")?)|"+ 

    // Hexadecimal strings 
    "((" + 
    // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt 
    "(0[xX]" + HexDigits + "(\\.)?)|" + 

    // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt 
    "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" + 

    ")[pP][+-]?" + Digits + "))" + 
     "[fFdD]?))" + 
     "[\\x00-\\x20]*");// Optional trailing "whitespace" 
+0

Où puis-je trouver "fpRegex"? –

+0

Cliquez sur le lien Double. Il a tout le code dont vous avez besoin –

+0

La regex est assez moche donc je pense que je préfère d'autres méthodes. Bonne alternative cependant. –

1

Vous pouvez implémenter une classe comme ceci:

class DoubleParser { 

    private Optional<Double> parsedOptional; 

    private DoubleParser(Optional<Double> parsedOptional) { 
     this.parsedOptional = parsedOptional; 
    } 

    public static DoubleParser parse(final String s) { 
     Double parsed = null; 
     try { 
      parsed = Double.valueOf(s); 
     } catch (NumberFormatException e) { 
      parsed = null; 
     } 

     return new DoubleParser(Optional.ofNullable(parsed)); 
    } 

    public double get() { 
     return get(0.0); 
    } 

    public double get(final double defaultValue) { 
     return parsedOptional.orElse(defaultValue); 
    } 

} 

Et puis utiliser comme ceci:

double lowVal, mediumVal, highVal; 
String lowString = "1.2", mediumString = "null", highString = "7.9"; 

lowVal = DoubleParser.parse(lowString).get(); 
mediumVal = DoubleParser.parse(mediumString).get(); 
highVal = DoubleParser.parse(highString).get(); 

// with default value if you want 
mediumVal = DoubleParser.parse(mediumString).get(Double.NaN); 
+0

Bonne solution, mais malheureusement, je ne peux pas utiliser cela dans Android, car il ne supporte pas Java 8. –

+1

@SinaMadani mon mauvais, ne peut pas attendre Java 8 sur Android moi-même – stjepano

0

Lorsque vous vous attendez à des échecs d'analyse, je trouve plus simple de ne pas utiliser du tout les méthodes basées sur les exceptions. En plus d'aboutir à un code plus concis, il peut être plus rapide de plusieurs ordres de grandeur puisqu'il évite le coût de lancer des exceptions.

Plutôt que d'écrire mes propres méthodes, c'est Guava à la rescousse comme d'habitude. Vous pouvez réécrire votre analyse avec Doubles.tryParse comme ceci:

Double lowVal, mediumVal, highVal; 
String lowString = "1.2", mediumString = "null", highString = "7.9";  

lowVal = Doubles.tryParse(lowString); 
mediumVal = Doubles.tryParse(mediumString); 
highVal = Doubles.tryParse(highString); 

Très concis!Notez que toutes les valeurs qui n'ont pas pu être analysées seront null après l'exécution. Vous n'avez pas réellement dit quelle valeur vous voulez assigner aux doubles si l'analyse échoue (et en fait votre exemple original ne compilera pas puisque les valeurs sont potentiellement non initialisées).

Supposons que vous vouliez affecter la valeur de 0,0 à toute transmission défaillante analyse syntaxique - vous pouvez utiliser Objects.firstNonNull() à faire:

Double lowVal, mediumVal, highVal; 
String lowString = "1.2", mediumString = "null", highString = "7.9";  

lowVal = Objects.firstNonNull(Doubles.tryParse(lowString), 0.0); 
mediumVal = Objects.firstNonNull(Doubles.tryParse(mediumString), 0.0); 
highVal = Objects.firstNonNull(Doubles.tryParse(highString), 0.0); 
0

J'ai décidé d'utiliser cette méthode:

public static double parseWithDefault(String value, double fallback) { 
    try { 
     return Double.parseDouble(value); 
    } catch (NumberFormatException NaN) { 
     return fallback; 
    } 
} 

Et alors peut faire des affectations comme ça:

lowVal = parseWithDefault(lowString, lowVal); 
mediumVal = parseWithDefault(mediumString, mediumVal); 
highVal = parseWithDefault(highString, highVal);