【问题标题】:comparing null BigDecimal from Java BigDecimal比较 Java BigDecimal 中的 null BigDecimal
【发布时间】:2014-02-26 22:48:58
【问题描述】:

我有以下代码:

Welcome to Scala version 2.10.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_45).

scala> val z: BigDecimal = null
z: BigDecimal = null

scala> z == null
res0: Boolean = true

看起来不错。不过……

scala> import java.math.{BigDecimal => JBigDecimal}
import java.math.{BigDecimal=>JBigDecimal}

scala> val x: JBigDecimal = null
x: java.math.BigDecimal = null

在REPL中,赋值会抛出NPE:

scala> val y: BigDecimal = x
java.lang.NullPointerException
    at scala.math.BigDecimal.toString(BigDecimal.scala:452)
    at scala.runtime.ScalaRunTime$.scala$runtime$ScalaRunTime$$inner$1(ScalaRunTime.scala:324)
    at scala.runtime.ScalaRunTime$.stringOf(ScalaRunTime.scala:329)
    at scala.runtime.ScalaRunTime$.replStringOf(ScalaRunTime.scala:337)
    at .<init>(<console>:10)
    at .<clinit>(<console>)
    at $print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)

使用惰性变量会出现我主要关心的问题。

scala> lazy val y: BigDecimal = x
y: BigDecimal = <lazy>

scala> y == null
res1: Boolean = false

有什么建议吗?这是最后一个比较一个错误吗? 我考虑过将这两个元素都包装在 Options 中,但我首先想了解为什么会发生这种情况。

此外,比较这两个 BigDecimal 也会导致另一个(可能不同,但相关)异常

scala> z == y
java.lang.NullPointerException
    at scala.math.BigDecimal.toLongExact(BigDecimal.scala:411)
    at scala.math.BigDecimal$$anonfun$isValidLong$1.apply$mcV$sp(BigDecimal.scala:196)
    at scala.math.BigDecimal.noArithmeticException(BigDecimal.scala:211)
    at scala.math.BigDecimal.isValidLong(BigDecimal.scala:196)
    at scala.math.BigDecimal.equals(BigDecimal.scala:190)
    at scala.runtime.BoxesRunTime.equalsNumNum(BoxesRunTime.java:168)

我过去常常因为使用断言而变得更有趣

一个经过修改的更具体的例子:

  test("Both cases should be true") {
    val x: JBigDecimal = null
    val y: JBigDecimal = null
    x should be (null)
    y should be (null)
    x == y should be (true)

    val i :BigDecimal = x
    val j :BigDecimal = y

    i == j should be (true)
  }

但是,比较 i == j 时会失败

此外,即使使用选项,通过将 JBigDecimal 隐式转换为 BigDecimal,我仍然可以获得 BigDecimal(null) 实例。

我测试了这个错误报告,当我运行BigDecimalBug 时,它的断言失败了。

到目前为止,我复制的唯一可以正常工作的方法如下:

it("test implicit conversions from null Java BigDecimal to Option[BigDecimal]"){
  val x: JBigDecimal = null
  val y: JBigDecimal = null
  x should be (null)
  y should be (null)
  x == y should be (true)

  val i :BigDecimal = x
  val j :BigDecimal = y

  implicit def convertJBigDecimalOption(javaBigDecimal: JBigDecimal): Option[BigDecimal] =
    Option(javaBigDecimal) map { x => BigDecimal(x.toString) }

  val p :Option[BigDecimal] = x
  val q :Option[BigDecimal] = y

  p should be('empty)
  q should be('empty)
}

【问题讨论】:

    标签: java scala implicit


    【解决方案1】:

    NullPointerException 发生是因为 REPL 在 val 分配之后调用 toString(),这会引发异常。这就是为什么它不使用惰性评估抛出异常的原因,因为它不会调用 toString()

    scala.math.BigDecimal 是一个拥有java.math.BigDecimal 的类,但拥有空值的scala.math.BigDecimal 实例本身并不是空引用。在您的示例中,(y.bigDecimal == null) 将评估为 true。

    无论如何,Option 的创建是有原因的,使用它而不是分配和检查空值是一个更好的主意。

    编辑:

    做这样的事情:

    val x : java.math.BigDecimal = null
    BigDecimal(x) == BigDecimal(x)
    

    .. 会抛出一个NullPointerException,因为BigDecimal 将不可避免地调用这个:

    def compare (that: BigDecimal): Int = this.bigDecimal compareTo that.bigDecimal
    

    .. 比较包裹的java.math.BigDecimals,和compareTo在找到null时抛出异常。

    【讨论】:

    • 我明白这一切,但没有说明我们现在创建了一个 BigDecimal(null),一旦评估,它就会在任何时候失败,而不是分配 null。
    • 在评估时不会失败,在调用toString 时会失败。为什么要BigDecimal(null) == null?我不知道另一个以这种方式工作的课程。无论您是否认为这是一个错误,您都很难在 scala 语言中获得类似的行为。
    • 参见 z == null。查看 BoxesRuntime:168,我们发现: if ((yn instanceof ScalaNumber) && !(xn instanceof ScalaNumber)) return yn.equals(xn);
    • 我不明白你在说什么。 val Z:BigDecimal = nullBigDecimal(null) 不同。
    • 错字,我的意思是最后一个例子。 z == y
    猜你喜欢
    • 2023-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-09
    • 2022-11-02
    • 1970-01-01
    • 2023-03-14
    相关资源
    最近更新 更多