該文章翻譯自Gson Tutorial Series系列教程。該篇主要闡述了Gson如何處理Float和Double類型的特殊值。
上一篇博客中,我們探討了如何使得JSON的轉換具有仁慈性。仁慈性意味著允許JSON某些地方不遵循標準而Gson依然能夠解析。在這篇博客中,我們將探究一種允許非標準輸入的情況:Gson如何處理Float和Double類型的特殊值(比如**Float.NEGATIVE_INFINITY)。
Float和Double類型的特殊值
在Java中,某些特殊情況下需要將值置為float型和double型。因此,在Java語言剛開始的時候,Float.NEGATIVE_INFINITY,Float.POSITIIVE_INFINITY以及Float.NaN以及他們對應的double型就以及存在了。遺憾的是,JSON標準不知道它們的價值,并沒有將它們作為標準的一部分。
讓我們引用Gson文檔中關于該問題的描述:
JSON規范的2.4章節不允許擁有特殊的double值(NaN,Infinity,-Infinity)。然而,Javascript標準(查看章節4.3.20,4.3.22,4.3.23)允許它們作為Javascript的合法值。甚至,大部分的JavaScript引擎接收這些在JSON中的特殊值而不會發生任何問題。因此,從實踐層面來看,即使JSON規范不支持它們,但接收這些值作為合法的JSON也是有理可尋的。
記得嗎?在上一篇仁慈性的博客中我們寫道,反序列化時Gson對于JSON標準具有很棒的靈活性,而在序列化時又是靈活的。前一部分依然是正確的,但是,這些特殊的float和double值是唯一的意外,它們使得Gson會內在的違反標準。
讓我們講得再透徹一點:如果你傳入的JSON使用了一個或多個那樣的float或double邊緣值,它們會被默認反序列化,而不會有任何問題。
如果你傳遞一個Float.POSITIVE_INFINITY作為值,Gson將會拋出異常,因為Gson不能根據標準來進行轉換。如果你需要傳遞這些特殊值,你需要使用GsonBuilder來明確的指定這些值可以轉換。Gson為你提供了serializeSpecialFloatingPointValues來處理。
是時候來看一個例子了。我們來創建一個用戶類,它擁有一個float類型的成員變量weight。
public class UserFloat {
String name;
Float weight;
public UserFloat(String name, Float weight) {
this.name = name;
this.weight = weight;
}
}
現在,復活節的巧克力兔女郎對我產生了負面影響,最后我的體重大增,因此我需要像下面那樣創建我的用戶實例:
UserFloat user = new UserFloat("Norman", Float.POSITIVE_INFINITY);
如果你將之傳遞給Gson,它將會拋出異常:
Gson gson = new Gson();
UserFloat user = new UserFloat("Norman", Float.POSITIVE_INFINITY);
String usersJson = gson.toJson(user); // will throw an exception
Gson將會給你一個IllegalArgumentException異常,它的陳述如下:
Infinity并不是JSON規范的有效double值。想要使用該行為,使用serializeSpecialFloatingPointValues()方法。
異常信息是非常有幫助的,并且已經提供給了我們解決辦法。我們需要使用GsonBuilder:
Float.POSITIVE_INFINITY
這將不會有任何異常,并且usersJson的內容是正確的:
GsonBuilder
當然了,這并不是100%的標準,因此你需要確認你的API是否能夠處理這些不尋常的值。
前瞻
本篇文章,你學會了Gson是如何處理費標準的JSON float值。默認情況下,Gson不允許序列化這些邊緣值。然而,你可以使用GsonBuilder來激活。
下一篇文章,我們將會探討為你的模型版本化。