Published 19 Sep, 2022

Java - Kotlin: java.lang.UnsupportedOperationException in MutableList add element

Category Java
Modified : Oct 03, 2022
47

I'm implementing a stack algorithm for study purpose in Kotlin

class Stack<T:Comparable<T>>(list:MutableList<T>) {

    var items: MutableList<T> = list


    fun isEmpty():Boolean = this.items.isEmpty()

    fun count():Int = this.items.count()

    fun push(element:T) {
        val position = this.count()
        this.items.add(position, element)
    }

    override  fun toString() = this.items.toString()

    fun pop():T? {
        if (this.isEmpty()) {
            return null
        } else {
            val item =  this.items.count() - 1
            return this.items.removeAt(item)
        }
    }

    fun peek():T? {
        if (isEmpty()) {
            return null
        } else {
            return this.items[this.items.count() - 1]
        }
    }

}

And I'm trying to execute using this code:

fun main(args: Array<String>) {

        var initialValue = listOf<Int>(10) as MutableList<Int>
        var stack = Stack<Int>(initialValue)
          stack.push(22)
        println(stack.count())
        println(stack.isEmpty())
        println(stack.pop())
        println(stack.count())
        println(stack.isEmpty())

    }

When I run the code I receive this error:

Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at Stack.push(Stack.kt:17)
at StackKt.main(Stack.kt:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

This is related with the follow line that is implemented in push(element:T) method:

 this.items.add(position, element)

The most weird thing is that I used a very similar code implementing a orderedArray and it works perfectly.

Do you have any idea of what I'm doing wrong ?

Answers

There are 2 suggested solutions here and each one has been listed below with a detailed description. The following topics have been covered briefly such as Algorithm, Java, Stack, Kotlin. These have been categorized in sections for a clear and precise explanation.

55

listOf<Int> is not truly mutable. According to the doc:

fun <T> listOf(vararg elements: T): List<T> (source) Returns a new read-only list of given elements. The returned list is serializable (JVM).

You should use mutableListOf<> instead.

The reason why as MutableList is permitted here is because listOf(10) returns Collections.singletonList(10) which returns a java.util.List (which Kotlin assumes implements the kotlin.collections.MutableList interface). So the compiler does not know it's not really mutable until the mutating method is called at runtime and throws the exception.


19

You can fix this by calling toMutableList() api rather than using smart cast (as).

Try: var initialValue = listOf< Int >(10).toMutableList()

Below is a working example:

fun main(){
    val x : List<String> = listOf("foo", "bar", "baz")
    //val y: MutableList<String> = x as MutableList<String> throws UnsupportedOperationException
    val y: MutableList<String> = x.toMutableList()
    y.add("sha")
    println(y) // [foo, bar, baz, sha]
}