Основная проблема заключается в том, что calculatedResults
мог быть изменен другим потоком между содержащим (if(calculatedResults.containsKey(n))
) и get (return calculatedResults[n]
).
Даже после проверки с помощью containsKey
calculatedResults[n]
может, следовательно, вернуть неправильный результат, включая null
, и такого способа проверки следует избегать.
Использование !!
обычно следует использовать только в случае крайней необходимости, потому что это может вызвать NPE. Это определенно хаки.
Используйте следующий синтаксис для решения проблемы:
calculatedResults[n]?.let {
return it
}
По сути, это хороший способ сказать
val result = calculatedResults[n]
if(result != null) {
return result
}
см. https://kotlinlang.org/docs/reference/null-safety.html#safe-calls
Еще лучше использовать встроенный getOrPut :
private fun q2(n: Int): Int {
return calculatedResults.getOrPut(n) { calcQ() }
}
private fun calcQ(): Int {
val q = ...
return q
}
Должен ли возвращаемый тип функции быть Int?
, потому что, хотя HashMap
может содержать ключ n, значение может быть нулевым? Разве это не значит, что HashMap
должно быть <Int, Int?>
?
Нет, вы правильно сделали, когда определили сигнатуру метода. Компилятор только жаловался, потому что то, что произошло в методе, не соответствовало этому. Если вы изменяете сигнатуру метода, вы просто перемещаете задачу в функцию, вызывающую q2
, не обрабатывая ее.