在Kotlin中,您可以创建一个data class
:
data class CountriesResponse(
val count: Int,
val countries: List<Country>,
val error: String)
然后,您可以使用它来解析JSON,例如,“{n:10}"。在这种情况下,您将拥有一个从Retrofit
、Fuel
或Gson
接收的对象val countries: CountriesResponse
,它包含以下值:count = 0, countries = null, error = null
.
在Kotlin + Gson - How to get an emptyList when null for data class中,您可以看到另一个示例。
当您稍后尝试使用countries
时,您会在此处收到例外状况:异常错误:如果您编写代码并在访问这些字段时使用?
,Android Studio将突出显示?.
并发出警告:Unnecessary safe call on a non-null receiver of type List<Country>
.
那么,我们应该在数据类中使用?
吗?为什么应用程序可以在运行时将null
设置为不可为空的变量?
2条答案
按热度按时间3wabscal1#
这是因为Gson使用了一个不安全的(如
java.misc.Unsafe
)示例构造机制来创建类的示例,绕过它们的构造函数,然后直接设置它们的字段。请参阅此问答以了解一些研究:Gson Deserialization with Kotlin, Initializer block not called。
因此,Gson忽略了构造逻辑和类状态不变量,因此不推荐将其用于可能受此影响的复杂类。它也忽略了setter中的值检查。
考虑一个支持Kotlin的序列化解决方案,比如Jackson(在上面链接的Q&A中提到过)或
kotlinx.serialization
。mi7gmzs62#
JSON解析器在两个本质上不兼容的世界之间进行转换-一个是Java/Kotlin,它具有静态类型和空值正确性;另一个是JSON/JavaScript,其中任何内容都可以是任何内容,包括
null
,甚至不存在,“强制”的概念属于您的设计,而不是语言。因此,差距是必然会发生的,必须以某种方式加以处理。一种方法是在最小的问题上抛出异常(这会让很多人当场生气),另一种方法是在运行中编造值(这也会让很多人生气,只是稍后)。
Gson采取了第二种方法,它默默地吞噬着缺席的田野;将对象设置为
null
,将基元设置为0
和false
,从而完全屏蔽API错误,并导致更下游的隐含错误。因此,我建议使用2阶段解析:
是的,这是两倍的工作量-但它可以立即查明API错误,并在您无法修复这些错误时为您提供处理这些错误的位置,例如:
是的,你可以使用一个更好的解析器,有更多的选择--但你不应该这样做。你应该做的是把解析器抽象出来,这样你就可以使用任何解析器。因为无论你现在找到的解析器多么先进和可配置,最终你都会需要一个它不支持的特性。这就是为什么我把Gson作为最低的共同标准。
There's an article,解释了在更大的存储库模式上下文中使用(和扩展)的这个概念。