如何使用相同的catch块处理解析数字?

时间:2016-02-19 18:32:47

标签: java exception-handling numberformatexception

我经常遇到需要解析数值的情况(例如使用Integer.parseInt或Double.parseDouble)并且我有多个值。问题是,我发现自己必须复制异常处理,它变得丑陋。例如,请使用以下代码:

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

处理这种情况是否有良好的模式?

我不想使用单次尝试捕获,因为我想继续解析剩余的数字。

我应该提一下,在这个例子中,值没有被初始化,而是在实际的程序代码中。只有在字符串值可解析时才会进行赋值。

7 个答案:

答案 0 :(得分:4)

只提取一个方法:

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

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

答案 1 :(得分:1)

Double的文档中,您可以解决问题。

  

为避免在无效字符串上调用此方法并抛出NumberFormatException,可以使用下面的正则表达式来筛选输入字符串

用parseDouble方法包装所有内容并按照说明进行操作

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

您的问题似乎正在用其他评论替换它

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

如果链接变得无效(应该永远不会发生),这就是正则表达式

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"

答案 2 :(得分:1)

您可以实现这样的类:

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

}

然后像这样使用它:

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

答案 3 :(得分:0)

我只会使用一个try-catch来获取所有值。

答案 4 :(得分:0)

这是一个使用标志和循环来防止再次发生异常的解决方案:

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

答案 5 :(得分:0)

当您期望解析失败时,我发现根本不使用基于异常的方法更简单。除了导致更简洁的代码之外,它还可以快几个数量级,因为它避免了抛出异常的代价。

不是像我自己的方法那样编写,而是像往常一样拯救番石榴。您可以使用Doubles.tryParse重写解析,如下所示:

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

非常简洁!请注意,执行此操作后,任何无法解析的值都将为null。如果解析失败,您实际上并没有说过要分配给双打的值(实际上您的原始示例将不会编译,因为值可能未初始化)。

假设您想将值0.0分配给任何失败的解析 - 您可以使用Objects.firstNonNull()来执行此操作:

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

答案 6 :(得分:0)

我决定使用这种方法:

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

然后可以像这样进行分配:

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