【问题标题】:Unexpected NullPointException with RxKotlin when mapping optionals映射选项时使用 RxKotlin 出现意外的 NullPointException
【发布时间】:2019-11-28 14:58:57
【问题描述】:

首先,我有以下 Moshi json。

@JsonClass(generateAdapter = true)
data class OrderDetails(
    @Json(name = "_id") val id: Int,
    @Json(name = "status") val status: String,
    @Json(name = "tableNo") val tableNo: Int,
    @Json(name = "serverId") val serverId: Int?,
    @Json(name = "items") val orderItems: List<OrderDetailsItem>
)

除 serverId 外,所有这些字段都应包含数据。 这些数据是从我可以允许用户选择订单的服务器获取的。

onSeletedOrder
   .map { it.orderDetails.serverId } //blows up here apparently.
   .filterNotNull() //have tried this but it doesn't matter.
   .flatMap { findServerBy(it) }
   .map { "${it.firstname} ${it.lastname}" }

当我映射到上面的 serverId 时,我遇到了 NPE。 有趣的是,地图(即使它是可选的)之后会进行不安全的强制转换。 我希望它在地图之后保持可选性。 我假设这是因为向后桥接 RxJava。 好奇是否有人对这是为什么有进一步的解释。

【问题讨论】:

  • RxJava 中不允许 Null 值,因此禁止映射到 null 并与 NPE 崩溃。您可以在map 之前使用filter { it.orderDetails.serverId != null } 进行预过滤。至于为什么map 在 Kotlin 中没有产生Optional&lt;T&gt; 类型,我不知道。
  • onSeletedOrder:Observable&lt;OrderDetails&gt;的类型是什么? Single?还有什么?
  • 类型是 PublishSubject

标签: kotlin rx-java2 rx-kotlin2


【解决方案1】:

RxJava 不允许在流中使用空值。理想情况下,您应该在项目进入流之前执行此过滤器,但如果您不能这样做,您可以使用一个空字符串来代替 null。

onSeletedOrder
   .map { it.orderDetails.serverId.orEmpty() }
   .filter { it.isNotEmpty() }
   .flatMap { findServerBy(it) }
   .map { "${it.firstname} ${it.lastname}" }

【讨论】:

  • 我对额外防御需求的反馈不满意,但这很有效。我想我可以比地图更早地进行过滤。所以过滤 { it.orderDetails.serverId != null } 然后映射 { it.orderDetails.serverId }
【解决方案2】:

对于“map, but exclude some elements”,RxJava有flatMapMaybeObservable以外的其他类型也可以有对应的返回类型):

// helper
fun <T> T?.toMaybe(): Maybe<T> = if (this != null) Maybe.just(this) else Maybe.empty<T>

onSeletedOrder
   .flatMapMaybe { it.orderDetails.serverId.toMaybe() }
   .flatMap { findServerBy(it) }
   .map { "${it.firstname} ${it.lastname}" }

【讨论】:

    【解决方案3】:

    最好的方法是使用可选数据格式化您的数据类。

    @JsonClass(generateAdapter = true)
    data class OrderDetails(
        @Json(name = "_id") val id: Int? = 0,
        @Json(name = "status") val status: String? = "Not active",
        @Json(name = "tableNo") val tableNo: Int? = 0,
        @Json(name = "serverId") val serverId: Int? = 0,
        @Json(name = "items") val orderItems: List<OrderDetailsItem>? = listOf()
    )
    

    您不会收到任何 NPE

    【讨论】:

    • 当我开始将这些特定的可选字段放入 RxJava 时,情况并非如此。
    • 有意思,我发现moshi不支持这个,基于这个github.com/square/moshi/issues/807你能不能试验一下使用,Kotlinx序列化。我一直在我的项目中使用它,并且涵盖了这个用例。只是想看看它是否适用于 RxJava 地图过滤器
    • 我会看看它,但从根本上说,正如我研究过的那样,RxJava 流中没有空安全性。为了适应我从 RxJava 收集到的内容,需要重写。这是一个很好的帖子,讨论了一些问题/差异 (github.com/reactor/reactor-core/issues/979)
    猜你喜欢
    • 2017-05-28
    • 2017-11-26
    • 1970-01-01
    • 1970-01-01
    • 2021-09-28
    • 2017-09-30
    • 2021-05-18
    • 2012-04-17
    • 2016-06-20
    相关资源
    最近更新 更多