我有一个domainPrice设置为BigDecimal数据类型的域类.现在我正在尝试创建一个比较价格的方法,但似乎我不能在BigDecimal数据类型中有比较运算符.我是否必须更改数据类型或是否有其他方法?
这不是关于如何比较两个BigDecimal
对象的问题 - 我知道你可以使用compareTo
而不是equals
这样做,因为equals
记录为:
与compareTo不同,此方法仅考虑两个BigDecimal对象的值和比例相等(因此通过此方法比较时2.0不等于2.00).
问题是:为什么equals
以这种看似违反直觉的方式指定了?也就是说,为什么能够区分2.0和2.00 很重要?
似乎必须有这样的理由,因为Comparable
指定compareTo
方法的文档指出:
强烈建议(尽管不要求)自然排序与equals一致
我想必须有一个很好的理由忽略这个建议.
是否有一种优雅的方式断言数字是平等的,而忽略了他们的类?我想在JUnit测试框架中使用它,例如
Assert.assertEquals(1,1L)
Run Code Online (Sandbox Code Playgroud)
失败的java.lang.AssertionError:expected:java.lang.Integer <1>但是:java.lang.Long <1>
我希望有一个很好的方法,只比较值,并使用int,long,float,byte,double,BigDecimal,BigInteger,你命名它...
我有一个JSF 2.2应用程序,用户必须输入BigDecimal
值<h:inputText>
.对于这样的输入字段,a valueChangeListener
被配置为在输入变化时被调用.这是XHTML代码:
<h:form id="theForm">
<h:inputText id="bd" value="#{bean.bd}"
valueChangeListener="#{bean.bdChangedListener()}"/>
<h:commandButton id="submit" value="Submit" />
</h:form>
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,这样做很好.bdChangedListener()
当值改变并按下提交按钮时,将调用该方法.该值已正确提交给模型.
但是,如果我进入1.1
并改变它1.10
,新的值被提交到模型,但valueChangeListener
在从来没有所谓!Debuging表明,其原因在于javax.faces.component.UIInput#compareValues()
.这种方法的JavaDoc
说:
如果新值与先前值不同,则返回true.首先通过将值传递给参数previous之前的equals方法来比较这两个值.如果该方法返回true,则返回true.如果该方法返回false,并且两个参数都实现java.lang.Comparable,则通过将值传递给参数previous之前的compareTo方法来比较这两个值.如果此方法返回0,则返回true,否则返回false.
所以在我看来,这是故意的.但为什么?
用户输入已更改,并且存在应用程序,其中a的比例BigDecimal
是相关的.所以JSF不应该忽略改变的输入,而是通知我!它使用新值更新模型,为什么它会跳过valueChangeListener-method?
我怎样才能避免这种行为并以干净的方式得到通知?(我知道我可以挂进制定者,但这不是我所谓的干净方式!)
有任何想法吗?
除了上面我想提到的,我已经读过像BigDecimal equals()和compareTo()这样的问题.我确实理解为什么BigDecimal equals()
和compareTo()
他们的行为一样,我说它是正确的.BigDecimal的行为不是问题,UIInput.compareValues()
而是问题.
此外,转换器(如评论或已删除的答案中所示)将无法保存我的一天.用户输入已正确转换,我需要BidDecimal,包括我的应用程序中的确切比例.任何返回BigDecimal的转换器都不会改变观察到的行为.
围绕BigDecimal的包装类可能会解决我的问题,但不是我认为的干净解决方案.我真的想知道为什么UIInput的行为方式.
我有以下同样的奇怪情况进入JUnit
测试.
所以我有这个测试方法:
@Test
public void getNavInfoTest() throws ParseException {
TirAliquotaRamoI expectedObject = new TirAliquotaRamoI();
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date date;
date = formatter.parse("2015-08-01");
Date dataInizio = formatter.parse("2015-08-01");
Date dataFine = formatter.parse("2100-12-31");
expectedObject.setDataElaborazione(date);
expectedObject.setTassoLordoAnnuoAppl(BigDecimal.ZERO);
expectedObject.setTassoGiornalieroNetto(BigDecimal.ZERO);
expectedObject.setAliquota(BigDecimal.ONE);
expectedObject.setDataInizio(dataInizio);
expectedObject.setDataFine(dataFine);
TirAliquotaRamoI tirAliquotaRamoI = pucManager.getNavInfo(date);
assertEquals(tirAliquotaRamoI.getAliquota(), expectedObject.getAliquota());
}
Run Code Online (Sandbox Code Playgroud)
最后,我只是测试tirAliquotaRamoI.getAliquota()
(从数据库查询获得)是否具有为创建的相同字段的相同值expectedObject
:
assertEquals(tirAliquotaRamoI.getAliquota(), expectedObject.getAliquota());
Run Code Online (Sandbox Code Playgroud)
因此,使用BigDecimal.ONE
constand 创建预期对象的字段,并使用调试器,我可以看到它的值是1
.
而tirAliquotaRamoI.getAliquota()
obtaind值1.000000000
因此,从理论上讲,两者都代表相同的值1,但测试失败,我得到:
java.lang.AssertionError: expected:<1.000000000> but was:<1>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
at com.fideuram.dbmanager.PucManagerTest.getNavInfoTest(PucManagerTest.java:90)
at …
Run Code Online (Sandbox Code Playgroud) 我正在运行这样的断言:
assertThat(obj.getTotal()).isEqualTo(BigDecimal.valueOf(4))
Run Code Online (Sandbox Code Playgroud)
我正进入(状态
期望:<4.00> 等于:<4>
所以我试过了
assertThat(obj.getTotal()).isEqualTo(BigDecimal.valueOf(4.00))
Run Code Online (Sandbox Code Playgroud)
期望:<4.00> 等于:<4.0>
我找到了一种解决方法,在该方法中我将预期值的比例设置4
为4.00
,但我必须为测试中的所有 BigDecimal 变量这样做似乎很令人恼火。AssertJ 有没有我不知道的更好的方法?
我有以下代码,但是我无法理解为什么两个bigdecimal不被视为相等
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
BigDecimal b = new BigDecimal(13.90);
BigDecimal b2 = new BigDecimal("13.9");
System.out.println(b.compareTo(b2));
}
}
Run Code Online (Sandbox Code Playgroud)
该代码输出1作为输出.那为什么会这样?不应该是0吗?
此外,如果我写13.9而不是"13.9",它给出0作为输出