【问题标题】:How to safely handle Java's wrapped primitives如何安全地处理 Java 的包装原语
【发布时间】:2015-02-13 14:02:24
【问题描述】:

我正在编写一个程序,它需要处理带有许多包装数字变量(例如 Long、Double、Integer 等)的对象。我如何安全地对这些变量执行数字运算而不必在任何地方进行空检查 em>?

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

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

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

【问题讨论】:

  • 为什么需要空检查?
  • 另外,为什么返回 0 比抛出 NPE 更安全?如果集合应该没有空值,那么这种装置将隐藏您的实际错误。得到一个 NPE 错误比给用户一个只有似乎有效的答案要好得多。
  • 为什么不能使用原语?
  • @Boann:在相加数字时避免 nullPointerExceptions。它们是可选的,因此它们通常是null
  • @barq:因为这些值是可选的,可以为空。很遗憾,我无法更改相关对象。

标签: java nullpointerexception primitive autoboxing


【解决方案1】:

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

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

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

在值可能不存在时使用Optional 的最大优势(在我看来)是,您可以在假设null 始终是错误的情况下开始依赖您的代码。

Optional 甚至提供了一种将可能为 null 的变量转换为 Optional 的简洁方法(例如,如果它被传递给您并且您无法控制它在进入代码时的值)。它的工作原理是这样的:

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

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

optVal.ifPresent(myList::add);

或者:

return optVal.orElse(27);

【讨论】:

  • 如果可以的话,我可能会使用它,但我无法更改包含可为空变量的对象,也无法使用 Java 8。不过仍然是一个很好的答案。
  • 好的,我将添加评论,说明您仍然可以使用 Optional。
  • 使用 Optional 不会使这种情况下的代码比进行空检查更短或更简单。
  • @Boann sumVariable += Optional.ofNullable(stupidObject.getNumberOfWhatever()).orElse(0); 对我来说至少更简单,也许不会更短......
  • @Boann 不,但它使它更清晰、更安全。如果你使用Integer,读者不知道它是否应该被允许为空。如果您使用Optional&lt;Integer&gt;,则非常清楚。
【解决方案2】:

你有一个非常具体的问题,并试图概括它而不考虑它。

  • 它可能是空值无效的前提条件。在您的情况下,您在 cmets 中声明它不是。但如果是的话,你应该处理它而不是隐藏它。

  • “安全”值可能不同。您选择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);
}

你用这个方法赢了什么?

【讨论】:

  • 注意:基于委托/lambda 演算(如 sprinter 的)的解决方案也很好,因为它们提供了更语义化的方式来做同样的事情。
  • 我想避免的是到处写空检查——它们使代码膨胀了很多。我希望有人回答类似于“嘿,有一个 Apache Commons 方法” :-)
【解决方案3】:

你可以使用谷歌的番石榴库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 的场景是不同的

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

【讨论】:

  • Guava 的Optional 与Java 8 相比,除了缺少Set&lt;T&gt; asSet() 方法外,还有什么优势?
  • @glglgl Java 8 的 Optional 灵感来自 Guava 的 Optional。如果你不能使用 Java 8,Guava 的 Optional 是一个很好的解决方案。
  • Guava 的 Optional 是个好主意,它已被添加到 Java 8 中。现在真的没有理由使用 Guava。事实上,为了与返回 OptionalStream 方法保持一致,最好使用 Java 8。
  • @sprinter 这不是真的。如果您必须使用 MATLAB R2012a 并希望它使用 Java 类,则这些 Java 类必须符合 Java 1.6...这是我在询问优势时完全忽略的一个方面...
  • @glglgl 是的,这很好。幸运的是,我可以在纯 Java 8 中工作,所以我没有遇到这个问题,但我明白你的观点,即 Guava 的向后兼容性在某些情况下是一个优势。
猜你喜欢
  • 1970-01-01
  • 2019-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-11
  • 1970-01-01
相关资源
最近更新 更多