rwallace
rwallace

Reputation: 33465

Kotlin MutableList initial capacity

I'm creating a list of values, in a context where it so happens that, though the values are being added one at a time, the eventual number is known in advance. This is in a function that will be called many times, so the faster it runs, the better.

In Java, I would use the ArrayList constructor that specifies an initial capacity, because in theory this makes it slightly faster because it avoids resizing.

In Kotlin, one normally uses mutableListOf(), but this does not allow an initial capacity; in theory this should result in slightly slower code.

Is the recommended/idiomatic Kotlin solution in this case:

  1. Go ahead and use the ArrayList constructor; ArrayList is a perfectly valid MutableList.
  2. Ignore the issue; the initial capacity never actually makes a measurable difference to speed.
  3. Something else?

Upvotes: 21

Views: 16399

Answers (3)

AouledIssa
AouledIssa

Reputation: 2824

You can wrap this mutableList() predefined function in a function like the following

fun <E> emptyMutableList(size: Int = 0): MutableList<E?> {
    return MutableList(size) {
        null
    }
}

this will return a MutableList of size size but also with null assigned to all of its cells. Now if you want to access any index value, your program will not crash with java.lang.IndexOutOfBoundsException like it would if you use the solution in the accepted answer. Here is what I mean:

fun <E> emptyMutableList(size: Int = 0): MutableList<E?> {
    return MutableList(size) {
        null
    }
}

fun <T> mutableListWithCapacity(capacity: Int): MutableList<T> =
    ArrayList(capacity)

fun main() {
    val mutableList1 = mutableListWithCapacity<Int>(20)
    val mutableList2 = emptyMutableList<Int>(20)
    
    mutableList1[10] // this will throw a java.lang.IndexOutOfBoundsException
    
    mutableList2[10] // this will not throw an exception but it will return null
}

Of course everything depends on how memory efficient vs crash-free you want your program to be.

Happy coding!

Upvotes: 1

Barakuda
Barakuda

Reputation: 788

Fill an immutable list

val doubles = List(5) { i -> i * 2 }
result --> [0, 2, 4, 6, 8]

Fill a mutable list of five elements with zeros

val ints = MutableList(5) { 0 }
result --> [0, 0, 0, 0, 0]

Upvotes: 7

Animesh Sahu
Animesh Sahu

Reputation: 8106

Updated Answer

I was actually confused with capacity and size. There is no implementation of using a default capacity MutableList currently in Kotlin stdlib.

You can make one yourself.

fun <T> mutableListWithCapacity(capacity: Int): MutableList<T> =
    ArrayList(capacity)

// creates a MutableList of Int with capacity of 5.
val mutableList = mutableListWithCapacity<Int>(5)

Outdated Answer

One of the reason why mutableListOf does not allow for default capacity is because default values in kotlin is not null.

However there is a utility function defined in kotlin.collections package.

public inline fun <T> MutableList(size: Int, init: (index: Int) -> T): MutableList<T> {
    val list = ArrayList<T>(size)
    repeat(size) { index -> list.add(init(index)) }
    return list
}

You can create a List with a List function or MutableList function with a default capacity and its mapping.

// creates a list of ints with default capacity of 10 and having nulls.
// But I highly doubt you should initialize it with a null since Kotlin is a null-safe language.
val list = MutableList<Int?>(10) { null }

But since there should not be nulls in Kotlin if it is intended use of non-null list else you have to do a null check using operators like ?. !!..

Upvotes: 13

Related Questions