What is the difference between List and Array types? It seems like we can perform the 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)

Solution

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 IntArrayDoubleArrayCharArrayetc. 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.
  • 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.
  • As to the usage, good practice is to prefer using lists over arrays everywhere except for performance critical parts of your code, the arguments are the same to those for Java.

This question was reposted from Stack Overflow