3
votes

NPE lors de l'utilisation de la carte {} sur ArrayList contenant des valeurs NULL

Je reçois

java.lang.NullPointerException: tentative d'appel d'une méthode virtuelle 'float java.lang.Number.floatValue ()' sur une référence d'objet nulle

sur le code suivant:

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

Je viens d'apprendre que ArrayList peut contenir des valeurs nulles (oookay). Cela voudrait dire que la valeur dans la fermeture de transformation de carte peut être NULL, non?

Mais cela ne peut pas être puisque la valeur n'est pas un type optionnel et le compilateur dit que if (value! = null) sera toujours vrai.

La question est donc de savoir comment éviter les NPE dans ce cas?


6 commentaires

Comment remplissez-vous la ArrayList ? le faites-vous en kotlin ou en java?


Bonne question. Il est en fait désérialisé par GSON donc ce devrait être Java


Bien entendu, la liste peut contenir null . Dans ce cas, le déballage automatique échouera (conversion de Float en float ), ce qui est évidemment fait ici. Une fois ce déballage automatique réussi, la variable value (qui est évidemment un float primitif) ne peut plus être null .


Le Json peut-il contenir des valeurs null ? Si oui, marquez la collection que vous obtenez de java comme ArrayList , puis filtrez les valeurs null possibles


Alors, quelles sont mes options pour éviter que cela échoue?


Je ne connais pas Kotlin. En Java brut, vous pouvez filtrer les éléments null : localHistory.stream (). Filter (Objects :: nonNull) .map (...) . Mais peut-être devriez-vous d'abord clarifier si les valeurs null sont autorisées ou non, ou comment les gérer lorsqu'elles se produisent.


3 Réponses :


2
votes

Si vous souhaitez simplement exclure les valeurs nulles dans la ArrayList , appelez mapNotNull au lieu de map . Voir ici pour plus de détails. Vous devez également gérer le cas où la valeur est nulle dans votre lambda, ce que vous pouvez faire avec le ? .let comme indiqué ci-dessous:

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


2 commentaires

Je reçois la suggestion du compilateur que ce n'est pas nécessaire lorsque j'essaye d'utiliser mapNotNull


Changez la déclaration en ArrayList pour indiquer au compilateur que la liste peut contenir des entrées nulles.



6
votes

Je suggère de marquer chaque paramètre d'une Collection que vous recevez de Java comme nullable (à moins bien sûr que vous ne le sachiez ne peut jamais être nul :

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

Ensuite, vous pouvez filtrer les null et faire votre opération de carte:

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

Gardez à l'esprit que chaque opération filter , map (et ainsi de suite) itérera toute la collection et en créera une nouvelle à chaque fois. Il vaut mieux utiliser Sequence code > s, qui sont itérés paresseusement.

Comme mentionné dans les commentaires, on peut utiliser filterNotNull pour filtrer directement toutes les valeurs nulles:

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


1 commentaires

Notez également que vous pouvez utiliser filterNotNull () au lieu de filter {it! = Null} .



0
votes

Un autre avec mapNotNull:

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


0 commentaires