欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

因BigDecimal類型數(shù)據(jù)引出的問(wèn)題詳析

 更新時(shí)間:2018年08月19日 14:23:13   作者:lensar  
Java在java.math包中提供的API類BigDecimal,用來(lái)對(duì)超過(guò)16位有效位的數(shù)進(jìn)行精確的運(yùn)算,下面這篇文章主要給大家介紹了因BigDecimal類型數(shù)據(jù)引出的問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

我們都知道,java中對(duì)大小數(shù),高精度的計(jì)算都會(huì)用到BigDecimal.但是在實(shí)際應(yīng)用中,運(yùn)用BigDecimal還是會(huì)遇到一些問(wèn)題,下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧

問(wèn)題描述:

程序中需要判斷一個(gè)字段是否為0(字段類型為BigDecimal),想都沒(méi)想,對(duì)象的判斷用equals?結(jié)果卻與預(yù)期有一定的差距,看下面代碼及運(yùn)行結(jié)果。

 public static void main(String[] args) {
  BigDecimal decimal1 = BigDecimal.valueOf(0);
  BigDecimal decimal2 = new BigDecimal("0.00");
  System.out.println("the result is " +decimal1.equals(decimal2));
 }

運(yùn)行結(jié)果:

the result is false

結(jié)論: BigDecimal類型比較相等不能簡(jiǎn)單的通過(guò)equals方法實(shí)現(xiàn)。

BigDecimal類的equals方法源碼如下:

 public boolean equals(Object x) {
  if (!(x instanceof BigDecimal))
   return false;
  BigDecimal xDec = (BigDecimal) x;
  if (x == this)
   return true;
  if (scale != xDec.scale)//這里會(huì)比較數(shù)字的精度
   return false;
  long s = this.intCompact;
  long xs = xDec.intCompact;
  if (s != INFLATED) {
   if (xs == INFLATED)
    xs = compactValFor(xDec.intVal);
   return xs == s;
  } else if (xs != INFLATED)
   return xs == compactValFor(this.intVal);

  return this.inflate().equals(xDec.inflate());
 }

看上面的注釋可以知道,BigDecimal類的equals方法會(huì)判斷數(shù)字的精度,看下面的代碼及運(yùn)行結(jié)果:

 public static void main(String[] args) {
  BigDecimal decimal1 = BigDecimal.valueOf(0).setScale(2);
  BigDecimal decimal2 = new BigDecimal("0.00").setScale(2);
  System.out.println("the result is " +decimal1.equals(decimal2));
 }

運(yùn)行結(jié)果:

the result is true

結(jié)論: 使用BigDecimal類equals方法判斷兩個(gè)BigDecimal類型的數(shù)據(jù)時(shí),需要設(shè)置精度,否則結(jié)果可能不正確。

思考:每次都設(shè)置精度比較麻煩,有其他方式進(jìn)行相等的比較嗎?

看了下BigDecimal的方法列表,有一個(gè)名為compareTo的方法,通過(guò)注釋可知,貌似可以進(jìn)行不同精度的比較,看下面的代碼。

 public static void main(String[] args) {
  BigDecimal decimal1 = BigDecimal.valueOf(1.1);
  BigDecimal decimal2 = new BigDecimal("1.10");
  System.out.println("the result is " +decimal1.compareTo(decimal2));
 }

運(yùn)行結(jié)果:

the result is 0

0表示兩個(gè)數(shù)相等,所有可以通過(guò)compareTo實(shí)現(xiàn)不同精度的兩個(gè)BigDecimal類型的數(shù)字是否相等的比較

引出的問(wèn)題:公司的項(xiàng)目中,為了避免由于精度丟失引起問(wèn)題,凡是有精度要求的字段用的都是BigDecimal類型。數(shù)據(jù)持久層用的是Mybatis框架,Mybatis的mapper文件中有些條件判斷用的是BigDecimal對(duì)應(yīng)的字段,如下:

<select id="selectByCondition" resultType="com.scove.demo.domain.Score">
 select * from tb_score where 1=1 
 <if test="score!=null and score!=0">
  and score&gt;#{score}
 </if>
 ...

score是一個(gè)BigDecimal類型的字段,score!=0 Mybatis是如何進(jìn)行判斷的,會(huì)不會(huì)用的是上面的equals方法?如果是那么項(xiàng)目上線會(huì)不會(huì)捅大簍子,想到這兒,有點(diǎn)怕了。寫(xiě)了個(gè)程序測(cè)了下,這樣寫(xiě)完全沒(méi)問(wèn)題,能夠達(dá)到我想要的目的。但是還是有點(diǎn)擔(dān)心,看看Mybatis底層是如何實(shí)現(xiàn)的吧,以免以后犯類似的錯(cuò)誤嘛。

經(jīng)過(guò)分析調(diào)試,很快就找到了關(guān)鍵代碼的位置,如下:

public class ExpressionEvaluator {

 public boolean evaluateBoolean(String expression, Object parameterObject) {
 Object value = OgnlCache.getValue(expression, parameterObject);
 if (value instanceof Boolean) {
  return (Boolean) value;
 }
 if (value instanceof Number) {
  return !new BigDecimal(String.valueOf(value)).equals(BigDecimal.ZERO);
 }
 return value != null;
 }
...
public final class OgnlCache {

....
 public static Object getValue(String expression, Object root) {
 try {
  Map<Object, OgnlClassResolver> context = Ognl.createDefaultContext(root, new OgnlClassResolver());
  return Ognl.getValue(parseExpression(expression), context, root);
 } catch (OgnlException e) {
  throw new BuilderException("Error evaluating expression '" + expression + "'. Cause: " + e, e);
 }
 }

用的是表達(dá)式求值,Ognl這個(gè)類的竟然沒(méi)有源碼,apache的官網(wǎng)上找了下,是有相應(yīng)的源碼的,只是需要單獨(dú)下載,真麻煩,算了不看了。據(jù)說(shuō)底層用的是Spring 的ognl表達(dá)式,我也不 關(guān)心了。但是以后如果不確定mapper中的test是否正確咋個(gè)辦?

想了下,還是寫(xiě)一個(gè)工具類在拿不準(zhǔn)的時(shí)候用一下吧,反正拿不準(zhǔn)的時(shí)候肯定很少,所以隨便寫(xiě)了簡(jiǎn)單的吧,如下:

 public static void main(String[] args) {
  ExpressionEvaluator evaluator = new ExpressionEvaluator();
  String expression = "score!=null and score!=0";
  DynamicContext context = new DynamicContext(new Configuration(), null);
  context.bind("score", BigDecimal.valueOf(0.1));
  Boolean flag = evaluator.evaluateBoolean(expression , context.getBindings());
  System.out.println("the result is " +flag);
 }

運(yùn)行結(jié)果:

the result is true

總結(jié)

開(kāi)發(fā)過(guò)程中,一定要細(xì)心去處理細(xì)節(jié)上的東西,不然一不小心就跳坑里了,輕則系統(tǒng)造成數(shù)據(jù)的不一致,修復(fù)數(shù)據(jù);重則造成重大的損失....

好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Java基礎(chǔ)之SpringBoot整合knife4j

    Java基礎(chǔ)之SpringBoot整合knife4j

    Swagger現(xiàn)在已經(jīng)成了最流行的接口文檔生成與管理工具,但是你是否在用的時(shí)候也在吐槽,它是真的不好看,接口測(cè)試的json數(shù)據(jù)沒(méi)法格式化,測(cè)試地址如果更改了還要去改配置,接口測(cè)試時(shí)增加token驗(yàn)證是真的麻煩…針對(duì)Swagger的種種缺點(diǎn),Knife4j就呼之欲出了.需要的朋友可以參考下
    2021-05-05
  • 關(guān)于@Component注解下的類無(wú)法@Autowired問(wèn)題

    關(guān)于@Component注解下的類無(wú)法@Autowired問(wèn)題

    這篇文章主要介紹了關(guān)于@Component注解下的類無(wú)法@Autowired問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 實(shí)例講解Java中random.nextInt()與Math.random()的基礎(chǔ)用法

    實(shí)例講解Java中random.nextInt()與Math.random()的基礎(chǔ)用法

    今天小編就為大家分享一篇關(guān)于實(shí)例講解Java中random.nextInt()與Math.random()的基礎(chǔ)用法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-02-02
  • Java使用ES?Client?調(diào)用滾動(dòng)查詢及Elasticsearch滾動(dòng)查詢Scrolling機(jī)制

    Java使用ES?Client?調(diào)用滾動(dòng)查詢及Elasticsearch滾動(dòng)查詢Scrolling機(jī)制

    Elasticsearch提供了一種稱為"滾動(dòng)查詢"(Scrolling)的機(jī)制,用于處理大型數(shù)據(jù)集的分頁(yè)查詢,這篇文章給大家介紹滾動(dòng)查詢的一般步驟及Java使用ESClient調(diào)用滾動(dòng)查詢的方法,感興趣的朋友一起看看吧
    2023-08-08
  • Sentinel中三種流控模式的使用詳解

    Sentinel中三種流控模式的使用詳解

    這篇文章主要為大家詳細(xì)介紹了Sentinel中三種流控模式(預(yù)熱模式,排隊(duì)等待模式和熱點(diǎn)規(guī)則)的使用,文中的示例代碼講解詳細(xì),感興趣的可以了解下
    2023-08-08
  • Schedule定時(shí)任務(wù)在分布式產(chǎn)生的問(wèn)題詳解

    Schedule定時(shí)任務(wù)在分布式產(chǎn)生的問(wèn)題詳解

    這篇文章主要介紹了Schedule定時(shí)任務(wù)在分布式產(chǎn)生的問(wèn)題詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • Spring整合Mybatis思路梳理總結(jié)

    Spring整合Mybatis思路梳理總結(jié)

    mybatis-plus是一個(gè) Mybatis 的增強(qiáng)工具,在 Mybatis 的基礎(chǔ)上只做增強(qiáng)不做改變,為簡(jiǎn)化開(kāi)發(fā)、提高效率而生,下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合Mybatis-plus案例及用法實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • 詳解Spring?@Lazy注解為什么能破解死循環(huán)

    詳解Spring?@Lazy注解為什么能破解死循環(huán)

    這篇文章主要來(lái)和大家探討一下Spring中的@Lazy注解為什么能破解死循環(huán),文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,需要的可以了解一下
    2023-07-07
  • mybatis?plus中如何編寫(xiě)sql語(yǔ)句

    mybatis?plus中如何編寫(xiě)sql語(yǔ)句

    這篇文章主要介紹了mybatis?plus中如何編寫(xiě)sql語(yǔ)句,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Java中類的初始化和實(shí)例化區(qū)別詳解

    Java中類的初始化和實(shí)例化區(qū)別詳解

    這篇文章主要介紹了Java中類的初始化和實(shí)例化區(qū)別詳解,類的初始化<BR>是完成程序執(zhí)行前的準(zhǔn)備工作,類的實(shí)例化(實(shí)例化對(duì)象)是指創(chuàng)建一個(gè)對(duì)象的過(guò)程,需要的朋友可以參考下
    2023-08-08

最新評(píng)論