识别解析错误的默认值(字符串 -> double/any 数字)

Default value to identify parsing error (String -> double/any numeric)

Java 在使用 "default value" 而不是异常时检查无效解析结果的最佳实践是什么?

我正在处理的(旧的)项目有一个故障安全实用程序方法来将 String 解析为 double,例如:

//null checks, LOG output etc removed for readability
double parseDouble(String input, double defaultValue){ 
  try{    
    return Double.parseDouble(input)
  } catch (Exception e){
    return defaultValue;
  }
}

现在以前的开发人员总是使用像 returnedValue = parseDouble(someString, -99); 这样的默认值和像 if(returnedValue == -99) 这样的检查来识别无效的解析结果。 (最终)添加的 SonarQube 服务器在 double 上使用 == 抱怨此检查,我想用 "correct" 检查替换这些检查。

处理此类情况的最佳做法是什么?

我个人会用 parseDouble(someString, Double.NaN); 并相应地检查 if(Double.isNan(returnedValue)。这是可行的解决方案吗?

编辑: 我忘了提到,实用程序 class 是不可编辑的(从我的角度来看),因此我正在研究如何轻松地 "fix" 现有代码。添加第三方库也不错,但(目前)也不可能。

在过去,我也会使用 NAN 或 POSITIVE_INFINITY 或 MAX_VALUE 或任何其他未使用的。现在我会使用 Optional-class。使用整数不可靠,因为转换和使用 null 是 Hoares one-billion-dollar 错误: null 是否意味着错误,未初始化,未给出?输入字符串是否为 null 或是否经过解析但不是有效的双精度表示形式?

基本上,您不希望在出现解析错误或空输入或用户输入默认值时返回默认值的方法。您需要一种方法来返回信息,无论是否有错误,如果没有,则返回解析后的值。 为了使您的代码更具可读性和更容易理解,我会编写这样的方法并在适当的地方使用它(而不是到处使用 copy-pasting 解决方法)。如果您不能将其放入现有实用程序 class,请制作您自己的附加实用程序 class。 如果您使用的是 Java 8,则可以使用 Optional-class。如果没有,则编写您自己的 Optional(或从某个库中获取)。 这是实用方法:

Optional<Double> parseDouble(String input) { 
  try {    
    return Optional.of(Double.parseDouble(input));
  } catch (Exception e) {
    return Optional.empty();
  }
}

使用方法如下:

String input = ...;
Optional<Double> parsedInput = parseDouble(input);
if (! parsedInput.isPresent()) {
    // print out warning and retry input or whatever
}
double convertedInput = parsedInput.value();

备注:

SonarQube 也会批评捕捉常见的 "Exception"。相反,您应该捕获 NumberFormatException 和 NullPointerException。 当调用者需要知道确切的原因时,您可以将方法 getEmptyReason() 添加到您的 Optional(或派生的 class)并将异常原因存储在那里。但我想在你的情况下,如果没有给出输入字符串(空或空),你想使用默认值,如果给出了值但无法解析,你想进行错误处理。在这种情况下,您可以使用:

Optional<Double> parseDouble(String input, double defaultValue) { 
  if (input == null || input.trim().length == 0) {
    return Optional.of(defaultValue);
  }
  try {    
    return Optional.of(Double.parseDouble(input));
  } catch (NumberFormatException e) {
    return Optional.empty();
  }
}