2
votes

Renvoyer correctement Int depuis Hashmap dans une fonction

J'ai une fonction dans Kotlin qui prend un argument Int et renvoie une valeur basée sur une formule. Pour accélérer les choses, je stocke les résultats intermédiaires dans un HashMap

return calculatedResults[n]!!

J'obtiens une incompatibilité de type de Int trouvé mais Int? requis à

return calculatedResults[n]

Je ne sais pas comment écrire correctement ceci. J'avais

private val calculatedResults = HashMap<Int, Int>()

private fun q2(n: Int): Int {
    if(calculatedResults.containsKey(n)) {
            return calculatedResults[n]
    }

    val q = ...
    calculatedResults[n] = q
    return q
}

Mais je ne suis pas sûr, si c'est un peu hacky.

Le type de retour de la fonction doit-il être Int? car si le HashMap peut contenir la clé n , la valeur peut être null ? Cela ne voudrait-il pas dire que le HashMap devrait être ?


0 commentaires

3 Réponses :


0
votes

Le problème sous-jacent est que calculéResults pourrait avoir été modifié par un autre thread entre contient ( if (calculéResults.containsKey (n)) ) et get ( renvoie les résultats calculés [n] ).

Même après avoir vérifié avec containsKey calculéResults [n] pourrait donc renvoyer un résultat erroné, y compris null , et cette façon de vérifier devrait être évité.

L'utilisation de !! ne doit généralement être utilisée que lorsque cela est absolument nécessaire, car cela peut provoquer un NPE. C'est définitivement piraté.

Utilisez la syntaxe suivante pour surmonter le problème:

private fun q2(n: Int): Int {
    return calculatedResults.getOrPut(n) { calcQ() }
}

private fun calcQ(): Int {
    val q = ...
    return q
}

En gros, c'est une bonne façon de dire

val result = calculatedResults[n]
if(result != null) {
    return result
}

voir https: // kotlinlang. org / docs / reference / null-safety.html # safe-calls

Encore mieux est d'utiliser le getOrPut :

calculatedResults[n]?.let {
    return it
}

Devrait le type de retour de la fonction est Int? car si le HashMap peut contenir la clé n, la valeur peut être nulle? Cela ne voudrait-il pas dire que le HashMap devrait être ?

Non, vous avez fait exactement la bonne chose quand vous avez défini la signature de la méthode. Le compilateur s'est plaint uniquement parce que ce qui s'est passé dans la méthode ne lui convenait pas. Si vous modifiez la signature de la méthode, vous déplacez simplement le problème vers la fonction appelant q2 sans le gérer.


0 commentaires

0
votes

Vous devriez envisager de réécrire ceci avec un code plus idiomatique. C'est une tâche assez basique de calculer une valeur si elle n'est pas déjà définie dans la carte:

fun q2(n: Int): Int {
    return calculatedResults.getOrPut(n) {
        42 //q
    }
}


0 commentaires

1
votes

getOrPut vérifiera s'il existe une valeur pour n . Si la valeur existe, elle sera renvoyée. Si les valeurs n'existent pas, la valeur renvoyée par le lambda sera affectée et ensuite renvoyée par getOrPut .

Jetez un œil à cet exemple:

fun calculate(n: Int) = n * 5 // some calculation

private fun q2(n: Int) = calculatedResults.getOrPut(n) {
    calculate(n)
}

Le type de retour de la fonction doit-il être Int? parce que tandis que le HashMap peut contenir la clé n la valeur peut être nulle? Ne serait-ce pas signifie que le HashMap devrait l'être?

Dans ce cas, la réponse à la question est évidemment "non" car si la valeur manque, il suffit de l'ajouter. Ainsi, la valeur renvoyée par q2 ne peut jamais être null.


0 commentaires