如何安全地处理 Java 的包装原语

How to safely handle Java's wrapped primitives

我正在编写一个程序,该程序需要处理包含许多包装数字变量的对象,例如 Long、Double、Integer 等。我如何才能安全地对这些对象执行数字运算而不必进行空值检查 无处不在?

我预计几乎每个 Java 程序员迟早都必须处理这个问题,所以我很惊讶没有数百篇博客文章和关于该主题的问题。

我目前的解决方案是通过这样的方法过滤所有数字:

private static safelyUnbox(Integer i) {
    return i == null ? 0 : i.intValue();
}
...
sumVariable += safelyUnbox(stupidObject.getNumberOfWhatever());

Java 8 提供了一个很好的替代方法来检查 null。如果一个整数(例如)可能有也可能没有值,那么您可以将其声明为 Optional<Integer>Optional class 有很多有用的实用程序,用于返回默认值、抛出异常、检查值是否存在等。

声明 Optional<Integer> 的好处是您向 reader 完全清楚 'no value' 是合法状态。维护您的代码的任何人都别无选择,只能使用 Optional 方法来决定如果值存在或不存在会发生什么。

另一方面,如果参数是强制性的,那么最简单的选择就是在使用它之前断言它不为空。

在我看来,只要值可能不存在,就使用 Optional 的巨大优势在于,您可以开始依赖代码,假设 null 始终是一个错误。

Optional 甚至提供了一种将可能为 null 的变量转换为 Optional 的巧妙方法(例如,如果它传递给您,而您在进入代码时无法控制它的值).它是这样工作的:

Optional<Integer> optVal = Optional.ofNullable(val);

然后您可以像使用任何其他变量一样使用新变量 Optional。例如:

optVal.ifPresent(myList::add);

或:

return optVal.orElse(27);

您可以使用 Google 的 Guava 库 Using and avoiding null

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

Optional 的最大优势不在于 readability:优势在于其防白痴性。如果您希望您的程序完全编译,它会迫使您积极考虑不存在的情况,因为您必须主动解包 Optional 并解决该情况。 Null 让人很容易忘记事情。

假设这种情况:

String meterReading=getValueFromRemoteSite();
System.out.println(meterReading.toLowerCase()); //Chances for NPE

但使用可选方案是不同的

Optional meterReading = Optional.of(getValueFromRemoteSite(););
if( meterReading.isPresent() )
{
   System.out.println( meterReading.get() );
}  

您有一个非常具体的问题,并且试图在不考虑的情况下将其概括。

  • 空值无效可能是一个先决条件。就您而言,您在评论中声明事实并非如此。但如果是,你应该处理它而不是隐藏它。

  • "safe" 值可能不同。您选择 0 是因为您要将数字相加,如果您要乘法(或将其用作商)怎么办?这是您的 safelyUnbox 方法所不具备的知识。

避免一概而论。对于您的情况,最好的代码很简单:

for(Integer integ : myCollection) {
  if (integ != null) {
    sum += integ;
  }
}

其他每种情况都有其最合适的解决方案。与

比较
for(Integer integ : myCollection) {
  sum += safeUnboxThatDefaultsto0(integ);
}

for(Integer integ : myCollection) {
  sum += safeUnbox(integ, 0);
}

你用这个方法赢了什么?