溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

使用JSONObject需要注意避免什么問(wèn)題

發(fā)布時(shí)間:2021-12-04 11:47:50 來(lái)源:億速云 閱讀:139 作者:小新 欄目:移動(dòng)開(kāi)發(fā)

這篇文章給大家分享的是有關(guān)使用JSONObject需要注意避免什么問(wèn)題的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。

問(wèn)題現(xiàn)象

在 Android 業(yè)務(wù)同步的邏輯代碼中,使用到了 JSONObject 來(lái)解析服務(wù)端的 JSON  數(shù)據(jù)。同時(shí)本地因?yàn)闃I(yè)務(wù)新增需求的緣故,在本地?cái)?shù)據(jù)庫(kù)中使用 JSONObject 緩存了包括水位等同步相關(guān)的信息,其中,水位值是 Long  型。但近期發(fā)現(xiàn)同步過(guò)程中下一次同步時(shí),傳遞給服務(wù)器的水位并不是上一次服務(wù)器返回的新水位,而是相差一些。以 301028292893495297L  為例,服務(wù)器返回這個(gè)水位之后,下次客戶端上傳的水位是 301028292893495296L,差值為 -1。

問(wèn)題排查

通過(guò)反復(fù)排查代碼邏輯,發(fā)現(xiàn)水位從服務(wù)端返回到下次請(qǐng)求之間,只經(jīng)過(guò)了以下轉(zhuǎn)換:

使用JSONObject需要注意避免什么問(wèn)題

認(rèn)真閱讀代碼不難發(fā)現(xiàn),Long 型的水位值保存在 JSON 對(duì)象中的時(shí)候轉(zhuǎn)成了 String 型,而在讀取的時(shí)候又當(dāng)作是 Long  型來(lái)處理。因此會(huì)有精度缺失的問(wèn)題,參見(jiàn)如下 JSONObject 的文檔:

由此可見(jiàn),在讀取 JSON 對(duì)象的某個(gè)值時(shí),如果原先是 String 型,讀取的時(shí)候當(dāng)作是 Long 型,是會(huì)將 String 型通過(guò) Double  進(jìn)行解析的,所以在值超過(guò) 2^52 時(shí)會(huì)有精度缺失的問(wèn)題。于是,遇到的問(wèn)題就可以解釋了。以下是 Double 的存儲(chǔ)格式規(guī)范:

使用JSONObject需要注意避免什么問(wèn)題

其中,Double 和 Long 的精度測(cè)試代碼很簡(jiǎn)單(輸入?yún)?shù)可以提供例如 301028292893495297L 這樣超過(guò) 2^52 的 long  值,會(huì)發(fā)現(xiàn)其返回值不為 0):

使用JSONObject需要注意避免什么問(wèn)題

Double 和 Long 的精度測(cè)試代碼很簡(jiǎn)單(輸入?yún)?shù)可以提供例如 301028292893495297L 這樣超過(guò) 2^52 的 long  值):

知道了問(wèn)題的根源,修復(fù)就一目了然了,在水位保存在 JSONObject 對(duì)象中時(shí),應(yīng)該當(dāng)作 Long 型而不是 String  型來(lái)保存;亦或者在讀取的時(shí)候也當(dāng)作是 String 型,然后通過(guò) Long.valueOf 等接口進(jìn)行解析。

另外,關(guān)于 JSON 對(duì)象中的值是 Long 型還是 String 型,其實(shí)比較容易被忽略。如果JSON 對(duì)象在使用 String  表示的時(shí)候,該值對(duì)應(yīng)處有引號(hào)就是 String 型。看如下的試用例就一目了然了:

使用JSONObject需要注意避免什么問(wèn)題

類似的問(wèn)題在網(wǎng)上隨意一搜,其實(shí)有許多人遇坑了,比如這個(gè)。

所以,盡管不能說(shuō)這個(gè)庫(kù)的設(shè)計(jì)是很失敗的,但肯定不算是一個(gè)設(shè)計(jì)良好的庫(kù)。因?yàn)槟銦o(wú)法直接從 API  名稱看出其內(nèi)在的潛在邏輯,容易導(dǎo)致使用者使用不當(dāng)。因此,經(jīng)驗(yàn)教訓(xùn)就是:使用第三方庫(kù)的時(shí)候,能看 API 文檔就看 API  文檔,切不可望文生義。當(dāng)然,這個(gè)問(wèn)題可能也僅限在 Android 中較老的代碼模塊,畢竟新的代碼都會(huì)使用 GSON 等類庫(kù)進(jìn)行 JSON  對(duì)象操作,也就不容易出現(xiàn)這樣的不易發(fā)現(xiàn)的問(wèn)題了。

當(dāng)然,單就這個(gè)問(wèn)題來(lái)看,其實(shí)是在新增業(yè)務(wù)邏輯的時(shí)候,沒(méi)有正確使用 JSONObject 對(duì)象的接口,Long 型的值不應(yīng)當(dāng)看成是 String  型進(jìn)行保存而又當(dāng)成是 Long 型來(lái)讀取,如果保存和讀取的接口保持對(duì)應(yīng),也就不會(huì)出現(xiàn)問(wèn)題了。不管怎么說(shuō),該問(wèn)題的教訓(xùn)是在使用 JSONObject  相關(guān)接口時(shí)要倍加小心謹(jǐn)慎。

備注:Github 上***的 JSON-Java 庫(kù)沒(méi)有這個(gè)問(wèn)題,可以放心使用。

使用JSONObject需要注意避免什么問(wèn)題

問(wèn)題解決

知道了問(wèn)題的根源,修復(fù)就一目了然了,在水位保存在 JSON 對(duì)象中時(shí),應(yīng)該當(dāng)作 Long 型而不是 String 型來(lái)保存;或者在讀取的時(shí)候也當(dāng)作是  String 型,然后通過(guò) Long.valueOf 等接口進(jìn)行解析。

感謝各位的閱讀!關(guān)于“使用JSONObject需要注意避免什么問(wèn)題”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI