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

Java 如何使用相同的catch块处理解析数字?,java,exception-handling,numberformatexception,Java,Exception Handling,Numberformatexception,我经常遇到这样一种情况:我需要解析一个数值(例如使用Integer.parseInt或Double.parseDouble),并且我有多个值。问题是,我发现自己必须复制异常处理,它变得丑陋。例如,以以下代码为例: double lowVal, mediumVal, highVal; String lowString = "1.2", mediumString = "null", highString = "7.9"; try { lowVal = parseDouble(lowStri

我经常遇到这样一种情况:我需要解析一个数值(例如使用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...
}
处理这种情况有好的模式吗

我不想使用一个try-catch,因为我想继续解析其余的数字


我应该提到的是,在这个例子中,这些值并没有初始化,但在实际的程序代码中它们会被初始化。只有当字符串值是可解析的时,才会发生赋值。

我只会对所有值使用一个try-catch

只需提取一个方法:

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, 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);
在你的文档中有你问题的解决方案

为了避免对无效字符串调用此方法并引发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"

您可以实现如下类:

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

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

与其写我自己的方法,不如像往常一样用番石榴来解救。您可以使用类似的方法重写解析:

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

假设您希望将值0.0分配给任何失败的解析-您可以使用:

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

我决定使用这种方法:

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

只需对所有三个使用一个try-catch,但我希望其余的继续执行。如果您试图在同一个try块中解析所有这些异常,那么每当抛出异常时,您如何继续解析其余的异常?也许可以将单个try捕获放在一个带有标志的循环中,以防止再次执行最后一个抛出的异常。我明白了。你不能继续解析;这就是RuntimeExceptions的问题所在,您要么暂停,要么捕获每一个异常。如果解析失败,您没有提到要分配给
lowVal
和朋友的内容。你不能只是“不在乎”,因为上面的代码甚至不会编译。它会抱怨lowVal可能未初始化:因为如果parseDouble失败,它将在分配任何值之前抛出,然后捕获异常,在作用域中保留一个未初始化的
lowVal
。但如果该值无效,我不想赋值。@SinaMadani
double
原语默认值为
0.0
,因此它无论如何都会有一个值。该值可能已经在代码中的其他地方赋值了,我只是将其用作一个简单的示例。我想我可以传入当前值并将其用作返回值。在哪里可以找到“fpRegex”?单击名为Double的链接。它有你需要的全部代码,正则表达式相当难看,所以我想我更喜欢其他方法。不过,这是一个不错的选择。你把它藏在一个方法中,就再也不必看到它丑陋的一面了:)那么为什么不使用try-catch呢?:)很好的解决方案,但不幸的是,我不能在Android中使用它,因为它不支持Java 8。@SinaMadani我的错,我自己不能在Android上等待Java 8。问题是冗长。我不介意有空的catch块,但我希望有一个解决方案可以减少代码,而不是增加代码。
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);