58 lines
2.8 KiB
Plaintext

== Why is this an issue?
When accessing `Map` elements by key, you should keep in mind that value might not be present. If value is not present, `null` will be returned. To make it possible, the type of returned value is nullable. In Kotlin, it's not usually convenient to operate with nullable types, so developers usually try to avoid them or convert them to non-nullable types. One of the possible solutions is to use `!!` (non-null assertion operator). If during the runtime the actual value applied to non-null asserrion operator was `null`, then `NullPointerException` will be thrown. While in some cases it could still be legitimate to use `!!`, accesing `Map` values is not one of them. Usage of a `!!` when accesing `Map` values is a bad practice and can lead to `NullPointerException` in Kotlin and potential crashes, if Java interop was involved.
== How to fix it
You should avoid using the non-null assertion operator when accessing `Map` elements.
Instead, you can:
* return an instance of a nullable type.
* use `getValue`. This will throw `NoSuchElementException` when an element is not present.
* use either `getOrElse` or `getOrDefault` functions and explicitly specify the behavior in case of a null value.
* use an elvis operator `?:` to specify the behavior in case of a null value.
=== Code examples
==== Noncompliant code example
This example will throw a `NullPointerException` at the `!!` operator because `map` doesn't have a key `123` and the result of `get(123)` will be null.
[source,kotlin]
----
val l = mapOf(1 to "one", 2 to "two", 3 to "five")
l.get(123)!! // Noncompliant
l[123]!! // Noncompliant
----
==== Compliant solution
By removing the non-null assertion operator the result of the `get(123)` call will return an instance of a nullable type, and the user can handle the potential `null` value properly.
[source,kotlin]
----
val l = mapOf(1 to "one", 2 to "two", 3 to "five")
l.get(123) // Compliant, returns nullable
l[123] // Compliant, returns nullable
l.getValue(123) // Compliant, throws NoSuchElementException
l.getOrElse(123 ) { "empty" } // Compliant, has default
l.getOrDefault(123, "empty") // Compliant, has default
l[123] ?: "empty" // Compliant, has default
----
== Resources
=== Documentation
* https://kotlinlang.org/docs/null-safety.html[Kotlin Documentation - Null safety]
* https://kotlinlang.org/docs/map-operations.html[Kotlin Documentation - Map-specific operations]
* https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/get-or-else.html[Kotlin Documentation - getOrElse]
* https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/get-or-default.html[Kotlin Documentation - getOrDefault]
=== Articles & blog posts
* https://medium.com/@igorwojda/kotlin-combating-non-null-assertions-5282d7b97205[Kotlin — combating non-null assertions (!!)]