Difference between List and Array types in Kotlin
Asked Answered
P

4

354

What is the difference between List and Array types?
It seems can make same operations with them (loops, filter expression, etc..), is there any difference in behavior or usage?

val names1 = listOf("Joe","Ben","Thomas")
val names2 = arrayOf("Joe","Ben","Thomas")

for (name in names1)
    println(name)
for (name in names2)
    println(name)
Publea answered 28/3, 2016 at 12:27 Comment(0)
C
537

Arrays and lists (represented by List<T> and its subtype MutableList<T>) have many differences, here are the most significant ones:

  • Array<T> is a class with known implementation: it's a sequential fixed-size memory region storing the items (and on JVM it is represented by Java array).

    List<T> and MutableList<T> are interfaces which have different implementations: ArrayList<T>, LinkedList<T> etc. Memory representation and operations logic of lists are defined in concrete implementation, e.g. indexing in a LinkedList<T> goes through the links and takes O(n) time whereas ArrayList<T> stores its items in a dynamically allocated array.

    val list1: List<Int> = LinkedList<Int>()
    val list2: List<Int> = ArrayList<Int>()
    
  • Array<T> is mutable (it can be changed through any reference to it), but List<T> doesn't have modifying methods (it is either read-only view of MutableList<T> or an immutable list implementation).

    val a = arrayOf(1, 2, 3)
    a[0] = a[1] // OK
    
    val l = listOf(1, 2, 3)
    l[0] = l[1] // doesn't compile
    
    val m = mutableListOf(1, 2, 3)
    m[0] = m[1] // OK
    
  • Arrays have fixed size and cannot expand or shrink retaining identity (you need to copy an array to resize it). As to the lists, MutableList<T> has add and remove functions, so that it can increase and reduce its size.

    val a = arrayOf(1, 2, 3)
    println(a.size) // will always be 3 for this array
    
    val l = mutableListOf(1, 2, 3)
    l.add(4)
    println(l.size) // 4
    
  • Array<T> is invariant on T (Array<Int> is not Array<Number>), the same for MutableList<T>, but List<T> is covariant (List<Int> is List<Number>).

    val a: Array<Number> = Array<Int>(0) { 0 } // won't compile
    val l: List<Number> = listOf(1, 2, 3) // OK
    
  • Arrays are optimized for primitives: there are separate IntArray, DoubleArray, CharArray etc. which are mapped to Java primitive arrays (int[], double[], char[]), not boxed ones (Array<Int> is mapped to Java's Integer[]). Lists in general do not have implementations optimized for primitives, though some libraries (outside JDK) provide primitive-optimized lists.

  • List<T> and MutableList<T> are mapped types and have special behaviour in Java interoperability (Java's List<T> is seen from Kotlin as either List<T> or MutableList<T>). Arrays are also mapped, but they have other rules of Java interoperability.

  • Certain array types are used in annotations (primitive arrays, Array<String>, and arrays with enum class entries), and there's a special array literal syntax for annotations. Lists and other collections cannot be used in annotations.

  • As to the usage, good practice is to prefer using lists over arrays everywhere except for performance critical parts of your code, the reasoning is the same to that for Java.

Capful answered 28/3, 2016 at 13:50 Comment(0)
P
71

The major difference from usage side is that Arrays have a fixed size while (Mutable)List can adjust their size dynamically. Moreover Array is mutable whereas List is not.

Furthermore kotlin.collections.List is an interface implemented among others by java.util.ArrayList. It's also extended by kotlin.collections.MutableList to be used when a collection that allows for item modification is needed.

On the jvm level, Array is represented by arrays. List on the other hand is represented by java.util.List since there are no immutable collections equivalents available in Java.

Pennington answered 28/3, 2016 at 12:40 Comment(4)
I'm not fully convinced here. What's mutable in Array? Only it's elements - the same in the List. The size of List is also fixed. – Unconnected
@Unconnected the following will compile val intArray = arrayOf(1,2,3); intArray[0] = 2 while this will not val intList = listOf(1,2,3); intList[0] = 2. The List indeed has a fixed size but MutableList which extends it doesn't hence it is possible that a val a:List<Int> will report different size on subsequent calls. – Pennington
Is it recommended to use List or ArrayList? – White
@White If you don't care about concrete implementation use List (probably 99% of the cases πŸ™‚). If you do care about implementation use ArrayList or LinkedList or any other concrete implementation. – Pennington
B
53

In additional to the above, identity comparison is also different:

val l1 = listOf("a")
val l2 = listOf("a")
var x = (l1 == l2) // => true

val a1 = arrayOf("a")
val a2 = arrayOf("a")
var y = (a1 == a2) // => false
Beowulf answered 15/10, 2020 at 21:21 Comment(3)
This answer helped me understand why data classes with arrays recommend that you implement the equals and hashCode functions, and do not when using lists. – Dome
reason for false op in-case of arrayOf()? – Satisfied
@UNREAL. When you use == with listOf, it checks if the content of the lists is the same. In the case of arrays, == checks for referential equality by default, meaning it checks if both sides refer to the same array instance. So, in the first comparison (l1 == l2), the lists have the same content, resulting in true. In the second comparison (al == a2), even though the content is the same, the arrays are different instances, resulting in false. – Hyperphysical
G
3

Explanation with a complex object

// lets define a data class
data class Color(var name : String)
// lets define all 3 - array, list and mutableList for this Color object

val array = arrayOf(Color("Red"))
val list = listOf(Color("Red"))
val mutableList = mutableListOf(Color("Red"))
  1. Methods on array
array.add(Color("Green"))  // Not Possible - cannot change size

array[0] = Color("Green")  // Possible - array object can be changed
array[0].name = "Green"   // Possible - object modification allowed by its class
  1. Methods on list
list.add(Color("Green")) // Not Possible - cannot change size
list[0] = Color("Green") // Not Possible - list object cannot be changed

list[0].name = "Green"   // Possible - object modification allowed by its class
  1. Methods on mutableList
mutableList.add(Color("Green"))   // Possible - can change size
mutableList[0] = Color("Green")   // Possible - can change object
mutableList[0].name = "Green"   // Possible - object modification allowed by its class

Conclusions :

  1. arrays and list have fixed size, so you cannot add or remove elements
  2. list cannot be modified, which means you cannot change the object it is holding
  3. array can be modified, which means you can change the object it is holding
  4. mutableList can do anything, change size or its objects

NOTE : This doesn't specify anything about the mutability of the object themselves. i.e. if the data class has some property as mutable (var), its property can be modified.

Gstring answered 3/11, 2023 at 17:37 Comment(0)

© 2022 - 2024 β€” McMap. All rights reserved.