Kotlin's List missing "add", "remove", Map missing "put", etc?

159,034

Solution 1

Unlike many languages, Kotlin distinguishes between mutable and immutable collections (lists, sets, maps, etc). Precise control over exactly when collections can be edited is useful for eliminating bugs, and for designing good APIs.

https://kotlinlang.org/docs/reference/collections.html

You'll need to use a MutableList list.

class TempClass {
    var myList: MutableList<Int> = mutableListOf<Int>()
    fun doSomething() {
        // myList = ArrayList<Int>() // initializer is redundant
        myList.add(10)
        myList.remove(10)
    }
}

MutableList<Int> = arrayListOf() should also work.

Solution 2

Defining a List collection in Kotlin in different ways:

  • Immutable variable with immutable (read only) list:

    val users: List<User> = listOf( User("Tom", 32), User("John", 64) )
    


  • Immutable variable with mutable list:

    val users: MutableList<User> = mutableListOf( User("Tom", 32), User("John", 64) )
    

    or without initial value - empty list and without explicit variable type:

    val users = mutableListOf<User>()
    //or
    val users = ArrayList<User>()
    
    • you can add items to list:
      • users.add(anohterUser) or
      • users += anotherUser (under the hood it's users.add(anohterUser))


  • Mutable variable with immutable list:

    var users: List<User> = listOf( User("Tom", 32), User("John", 64) )
    

    or without initial value - empty list and without explicit variable type:

    var users = emptyList<User>()
    
    • NOTE: you can add* items to list:
      • users += anotherUser - *it creates new ArrayList and assigns it to users


  • Mutable variable with mutable list:

    var users: MutableList<User> = mutableListOf( User("Tom", 32), User("John", 64) )
    

    or without initial value - empty list and without explicit variable type:

    var users = emptyList<User>().toMutableList()
    //or
    var users = ArrayList<User>()
    
    • NOTE: you can add items to list:
      • users.add(anohterUser)
      • but not using users += anotherUser

        Error: Kotlin: Assignment operators ambiguity:
        public operator fun Collection.plus(element: String): List defined in kotlin.collections
        @InlineOnly public inline operator fun MutableCollection.plusAssign(element: String): Unit defined in kotlin.collections


see also: https://kotlinlang.org/docs/reference/collections.html

Solution 3

Agree with all above answers of using MutableList but you can also add/remove from List and get a new list as below.

val newListWithElement = existingList + listOf(element)
val newListMinusElement = existingList - listOf(element)

Or

val newListWithElement = existingList.plus(element)
val newListMinusElement = existingList.minus(element)

Solution 4

Apparently, the default List of Kotlin is immutable. To have a List that could change, one should use MutableList as below

class TempClass {
    var myList: MutableList<Int>? = null
    fun doSomething() {
        myList = ArrayList<Int>()
        myList!!.add(10)
        myList!!.remove(10)
    }
}

Updated Nonetheless, it is not recommended to use MutableList unless for a list that you really want to change. Refers to https://hackernoon.com/read-only-collection-in-kotlin-leads-to-better-coding-40cdfa4c6359 for how Read-only collection provides better coding.

Solution 5

In Kotlin you must use MutableList or ArrayList.

Let's see how the methods of MutableList work:

var listNumbers: MutableList<Int> = mutableListOf(10, 15, 20)
// Result: 10, 15, 20

listNumbers.add(1000)
// Result: 10, 15, 20, 1000

listNumbers.add(1, 250)
// Result: 10, 250, 15, 20, 1000

listNumbers.removeAt(0)
// Result: 250, 15, 20, 1000

listNumbers.remove(20)
// Result: 250, 15, 1000

for (i in listNumbers) { 
    println(i) 
}

Let's see how the methods of ArrayList work:

var arrayNumbers: ArrayList<Int> = arrayListOf(1, 2, 3, 4, 5)
// Result: 1, 2, 3, 4, 5

arrayNumbers.add(20)
// Result: 1, 2, 3, 4, 5, 20

arrayNumbers.remove(1)
// Result: 2, 3, 4, 5, 20

arrayNumbers.clear()
// Result: Empty

for (j in arrayNumbers) { 
    println(j) 
}
Share:
159,034

Related videos on Youtube

Elye
Author by

Elye

Android Design, Development and Deployment

Updated on March 08, 2021

Comments

  • Elye
    Elye about 3 years

    In Java we could do the following

    public class TempClass {
        List<Integer> myList = null;
        void doSomething() {
            myList = new ArrayList<>();
            myList.add(10);
            myList.remove(10);
        }
    }
    

    But if we rewrite it to Kotlin directly as below

    class TempClass {
        var myList: List<Int>? = null
        fun doSomething() {
            myList = ArrayList<Int>()
            myList!!.add(10)
            myList!!.remove(10)
        }
    }
    

    I got the error of not finding add and remove function from my List

    I work around casting it to ArrayList, but that is odd needing to cast it, while in Java casting is not required. And that defeats the purpose of having the abstract class List

    class TempClass {
        var myList: List<Int>? = null
        fun doSomething() {
            myList = ArrayList<Int>()
            (myList!! as ArrayList).add(10)
            (myList!! as ArrayList).remove(10)
        }
    }
    

    Is there a way for me to use List but not needing to cast it, like what could be done in Java?

    • Darwind
      Darwind over 5 years
      Just a comment to why you can't do myList = null and then later on call add without !!. You could overcome this by using the lateinit keyword in front of your property like so: lateinit var myList: List<Int> this way you won't need to initialise the list immediately, but you guarantee to the compiler that you will initialise it before using the list the first time. It's a smoother solution, but it puts a responsibility on you as a developer.
  • Elye
    Elye almost 8 years
    Nice and well written answer. I'm picking yours as the model answer despite having mine below :)
  • fulvio
    fulvio almost 8 years
    You're correct about using MutableList, however initializing it with null won't work. Only safe or non-null asserted calls are allowed on a nullable receiver of type MutableList<Int>.
  • Elye
    Elye almost 8 years
    It works on my end, and no error found. I don't need to initialize it unless when I need it when doSomething
  • Kirill Rakhman
    Kirill Rakhman almost 8 years
    You don't need to make the list nullable if you initialize it immediately. I edited your answer.
  • Darwind
    Darwind over 5 years
    @Elye I know this is an old answer and question, but using lateinit instead of making the list nullable is the proper way of going about this issue. Don't remember whether lateinit was added from the beginning of Kotlin though, but this is definitely the solution nowadays to use it :-)
  • CoolMind
    CoolMind over 5 years
    That means that list2 is a mutable list, see stackoverflow.com/questions/43114367/….
  • BENN1TH
    BENN1TH over 4 years
    thanks and worked well with business logic within the apply method, even used anotherList.ForEach {add(foo)} inside the .appy{}