1

Why I'm getting "java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0" while running next code??? :

val totalList = mutableListOf<MutableList<Int>>()

fun main() {
    for (i in 0..15) {
        for (j in 0..10) {
            *some operations and calculations with **var element of type Int***
            totalList[i].add(element)
        }
    }
}

I was thinking that in such case while iterating through 'j' it should add elements to mutableList[i], after this it should start adding elements to mutableList[i + 1] etc.... But instead I am recieving IndexOutOfBoundsException....

1
  • 3
    totalList[0] doesn't exist, you need to initialize it with something like totalList.add(mutableListOf()) before you can add something to that inner list Commented Dec 9, 2022 at 12:55

1 Answer 1

4

val totalList = mutableListOf<MutableList<Int>>()

All this does is create one list which is going to contain MutableList<Int> items. Right now, there's nothing in it (you've supplied no initial elements in the parentheses).

Skip forward a bit, and you do this:

totalList[0].add(element)

You're trying to get the first element of that empty list and add to it. But there is no first element (index 0) because the list is empty (length 0). That's what the error is telling you.

There's lots of ways to handle this - one thing you could do is create your lists up-front:

// create the 16 list items you want to access in the loop
// (the number is the item count, the lambda generates each item)
val totalList = MutableList(16) { mutableListOf<Int>() }

// then refer to that list's properties in your loop (no hardcoded 0..15)
for (i in totalList.indices) {
    ...
    // guaranteed to exist since i is generated from the list's indices
    totalList[i].add(element)
}

Or you could do it the way you are now, only using getOrElse to generate the empty list on-demand, when you try to get it but it doesn't exist:

for (i in 0..15) {
    for (j in 0..10) {
        // if the element at i doesn't exist, create a list instead, but also
        // add it to the main list (see below)
        totalList.getOrElse(i) {
            mutableListOf<Int>().also { totalList.add(it) }
        }.add(element)
    }
}

Personally I don't really like this, you're using explicit indices but you're adding new list items to the end of the main list. That implicity requires that you're iterating over the list items in order - which you are here, but there's nothing enforcing that. If the order ever changed, it would break.

I'd prefer the first approach - create your structure of lists in advance, then iterate over those and fill them as necessary. Or you might want to consider arrays instead, since you have a fixed collection size you're "completing" by adding items to specific indices


Another approach (that I mentioned in the comments) is to create each list as a whole, complete thing, and then add that to your main list. This is generally how you do things in Kotlin - the standard library contains a lot of functional tools to allow you to chain operations together, transform things, and create immutable collections (which are safer and more explicit about whether they're meant to be changed or they're a fixed set of data).

for (i in 0..15) {
    // map transforms each element of the range (each number) to an item,
    // resulting in a list of items
    val items = (0..10).map { j ->
        // do whatever you're doing

        // the last expression in the lambda is its resulting value,
        // i.e. the item that ends up in the list
        element
    }

    // now you have a complete list of items, add them to totalList
    totalList.add(items)
}

(Or you could create the list directly with List(11) { j -> ... } but this is a more general example of transforming a bunch of things to a bunch of other things)

That example there is kinda half and half - you still have the imperative for loop going on as well. Writing it all using the same approach, you can get:

val totalList = (0..15).map { i ->
    (0..10).map { j ->
        // do stuff
        element
    }
}

I'd probably prefer the List(count) { i -> ... } approach for this, it's a better fit (this is a general example). That would also be better since you could use MutableList instead of List, if you really need them to be mutable (with the maps you could just chain .toMutableList() after the mapping function, as another step in the chain). Generally in Kotlin, collections are immutable by default, and this kind of approach is how you build them up without having to create a mutable list etc. and add items to it yourself

Sign up to request clarification or add additional context in comments.

4 Comments

Got it! Thanks a lot! Maybe you could also answer hot to initialize it later?? For example, number of lists is unknow yet and I need to use it later as public variable....
@vad070 Im not sure what you mean - you initialise it when you create it! If you want to start with an empty list (e.g. other things are looking at it, so you need an initial "empty" state) then you can add your empty list items to that whenever you want - before you start filling them in the for loops seems like a good time, since those empty lists are really an intermediate state between "no stuff" and "here's all the stuff". Or you could create the list item and fill it before adding it to totalList - I'll edit to show you how to do that
I'm really thankfull for your help, examples are really awesome!!! Will test them on practice!!!
@vad070 no worries! Also just in case, you know 0..10 goes from 0 to 10 inclusive, right? So you get 11 items? I've been referencing that in the answer but I just wanted to make sure you knew - if you want up to (but not including) 10, you can do 0 until 10. Sorry if you already knew, it's just an 11-item list looks suspicious!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.