测试JSP EL表达式中BigDecimal值是否为零

Joh*_*n S 19 java jsp el bigdecimal

以下并不总是像您期望的那样:

<c:if test="${someBigDecimal == 0}">
Run Code Online (Sandbox Code Playgroud)

如果someBigDecimal的值为0,但其标度不是0,则==操作返回false.也就是说,当someBigDecimal是new BigDecimal("0")时返回true,但是当someBigDecimal是new BigDecimal("0.00")时返回false.

这是由JSP 2.0,2.1和2.2规范产生的,它们声明:

对于<,>,<=,> =:

如果A或B是BigDecimal,则将A和B强制转换为BigDecimal并使用A.compareTo(B)的返回值.

对于==,!=:

如果A或B是BigDecimal,则将A和B强制转换为BigDecimal,然后:

  • 如果运算符是==,则返回A.equals(B)
  • 如果操作符是!=,则返回!A.equals(B)

这意味着==!=运算符会导致对.equals()方法的调用,该方法不仅会比较值,还会比较BigDecimals的比例.其他比较运算符导致对.compareTo()方法的调用,该方法仅比较值.

当然,以下方法可行:

<c:if test="${not ((someBigDecimal < 0) or (someBigDecimal > 0))}">
Run Code Online (Sandbox Code Playgroud)

但这是相当丑陋的,有没有更好的方法来做到这一点?

McD*_*ell 11

在JSP 2.2 EL及以上版本中,此表达式将评估为true:

${someBigDecimal.unscaledValue() == 0}
Run Code Online (Sandbox Code Playgroud)

这将避免任何精度损失,但假设someBigDecimal始终是类型BigDecimal.

一个自定义EL函数可能是旧版本的EL的最佳方法:

${fn:isZero(someBigDecimal)}
Run Code Online (Sandbox Code Playgroud)

问题的核心是这个Java代码的计算结果是false因为它ZERO具有一个规模,0而new BigDecimal具有非零规模:

BigDecimal.ZERO.setScale(3).equals(BigDecimal.ZERO)
Run Code Online (Sandbox Code Playgroud)