Skip to main content
Donovan LaDuke - Developer

Hidden Gems of the Kotlin Standard Library - List

One of the greatest things about working in Kotlin is access to the Kotlin Standard Library. This extensive catalogue of types and helper functions assist in writing streamlined and efficient code. All this while not relying on excessive external dependencies or requiring each codebase to reimplement the same functionality over and over again. This is an overview of five hidden gems in the Standard Library.

orEmpty #

Dealing with nullable list can be a pain as calling functions on it requires a null traversal call for each function.

fun printDoubleStrings(
  strings: List<String>?
) {
  strings
    ?.map { "$it $it" }
    ?.forEach { println(it) }
}

By using the orEmpty function to covert a nullable list to an empty list, that can all be avoided.

fun printDoubleStrings(
  strings: List<String>?
) {
  strings
    .orEmpty()
    .map { "$it $it" }
    .forEach { println(it) }
}

Check out the docs here

filterIsInstance #

When leveraging a list of items that is of a interface or sealed class type, filtering by the type can be an effective way to work with the list.

sealed class Result {
  data class Success(
    val content: Float
  ): Result()
  data class Failure(
    val message: String
  ): Result()
}

fun logErrors(results: List<Result>) {
  val failures = results.filter {
    it is Result.Failure
  }

  println("Failure Messages")
  failures.forEach {
    println(
        (it as Result.Failure).message
    )
  }
}

This code can be streamlined by using filterIsInstance to only get objects of a specific type from the list. This also changes the type of the list downstream to the filtered type, removing unnecessary casting and type checking.

sealed class Result {
  data class Success(
    val content: Float
  ): Result()
  data class Failure(
    val message: String
  ): Result()
}

fun logErrors(results: List<Result>) {
  val failures = results
    .filterIsInstance<Result.Failure>()

  println("Failure Messages")
  failures.forEach {
    println(it.message)
  }
}

Check out the docs here

distictBy #

If a list should only have unique elements inside, using distinct will remove duplicates. But if the logic is not that simple, then the distinctBy function can be used.

data class Message(
  val id: Int,
  val content: String,
)

fun distinctMessages(
  messages: List<Message>
): List<Message> {
  return messages
    .distinctBy { it.id }
}

Check out the docs here

chunked #

If a list needs broken up into smaller lists of a given size, the chunked function can be used. This is helpful for creating a paged list if, for example, no more than a certain number of elements should be shown at a given time. As an additional note, if the list is not evenly divisible, the final list will contain the remaining elements.

fun pagedNumbers(
  range: IntRange
): List<List<Int>> {
  return range
    .toList()
    .chunked(5)
}

Check out the docs here

random #

This is just a fun helper that selects a random element from the list.

fun greetUser() {
  val greetings = listOf(
    "Hello!",
    "Hey!",
    "Hola!",
    "Salut!",
  )
  
  println(greetings.random())
}

Check out the docs here

Conclusion #

The Kotlin Standard Library is full of gems like this. Hopefully this has brought inspiration to look for more interesting functionality available through the Standard Library. Until next time, thanks!

Did you find this content helpful?

Please share this post and be sure to subscribe to the RSS feed to be notified of all future articles!

Want to go above and beyond? Help me out by sending me $1 on Ko-fi. It goes a long way in helping run this site and keeping it advertisement free. Thank you in advance!

Buy me a Coffee on Ko-fi