在包含 NULL 的 ArrayList 上使用 map 时的 NPE

Posted

技术标签:

【中文标题】在包含 NULL 的 ArrayList 上使用 map 时的 NPE【英文标题】:NPE when using map on ArrayList containing NULLs在包含 NULL 的 ArrayList 上使用 map 时的 NPE 【发布时间】:2019-08-05 02:06:24 【问题描述】:

我明白了

java.lang.NullPointerException:尝试调用虚拟方法 'float java.lang.Number.floatValue()' 在空对象引用上

关于以下代码:

val localHistory: ArrayList<Float> = ArrayList<Float>()
...    
val strHistory = localHistory.map  value -> decoration.decoratedValue(ref.format, value) 

我刚刚了解到 ArrayList 可能包含空值 (oookay)。这意味着地图转换闭包中的 value 可能为 NULL,不是吗?

但这不可能,因为 value 不是可选类型,并且编译器说 if (value != null) 将始终为真。

那么问题是在这种情况下如何避免 NPE?

【问题讨论】:

您是如何填写ArrayList 的?你是用 kotlin 还是 java 做的? 好问题。它实际上是由 GSON 反序列化的,所以它应该是 Java 当然,列表可以包含null。在这种情况下,自动拆箱将失败(从Float 转换为float),这显然是在这里完成的。一旦这个自动拆箱成功,变量value(这显然是一个原始的float)就不能再是null了。 Json 可以包含任何null 值吗?如果是,请将您从 java 获得的集合标记为 ArrayList&lt;Float?&gt;,然后过滤掉可能的 null 那么我有什么选择可以防止这种情况失败? 【参考方案1】:

我建议将您从 Java 收到的 Collection 中的每个参数都标记为可为空(当然,除非您知道它永远不可能是 null

val floats: List<Float?> = someJavaClass.getFloats()

然后您可以过滤掉nulls 并进行地图操作:

val newFloats: List<Float> = floats
    .filter  it != null 
    .map  it + 1 

请记住,每个filtermap(等等)操作都会迭代整个集合并每次都创建一个新集合。你最好使用Sequences,它是惰性迭代的。

正如 cmets 中提到的,可以使用filterNotNull 直接过滤掉所有空值:

val newFloats: List<Float> = floats
    .filterNotNull()
    .map  it + 1 

mapNotNull 只保留映射函数不返回null 的值,这也消除了filterNotNull

val newFloats: List<Float> = floats
    .mapNotNull  it?.plus(1) 

我能想到的另一个结构适用于您的示例,尽管它非常不可读且很复杂。但这里是:

val strHistory = localHistory
    .mapNotNull  decoration.decoratedValue(ref.format, it ?: return@mapNotNull null) 

【讨论】:

另请注意,您可以使用filterNotNull() 而不是filter it != null 【参考方案2】:

如果您只想排除ArrayList 中的空值,请调用mapNotNull 而不是map。详情请见here。

您还需要处理 value 在您的 lambda 中为 null 的情况,您可以使用 ?.let 进行处理,如下所示:

localHistory.mapNotNull  value -> value?.let  decoration.decoratedValue(ref.format, it)  

【讨论】:

我得到编译器建议,当我尝试使用 mapNotNull 时没有必要 将声明更改为ArrayList&lt;Float?&gt; 以告诉编译器该列表可能包含空条目。【参考方案3】:

还有一个 mapNotNull:

val strHistory = localHistory.mapNotNull  it ?: return@mapNotNull null
    decoration.decoratedValue(ref.format, it) 

【讨论】:

以上是关于在包含 NULL 的 ArrayList 上使用 map 时的 NPE的主要内容,如果未能解决你的问题,请参考以下文章

使用 Java 流检查 ArrayList 内容

在带有整数数组的 ArrayList 上使用 contains

在 Java 中序列化和保存 double [] 的 ArrayList

使用 volley 将 ArrayList 发送到服务器时在响应中收到 null

<set> 中的无效属性:JSP 的新 ArrayList 中的“null”

如何使我的函数在 ArrayList 上运行得与“包含”一样快?