Getting the size
Every Kotlin array knows how many elements it holds. You read that number from its size property. It is a property, not a function, so there are no parentheses after it.
val ourArray = intArrayOf(50, 40, 30)
println(ourArray.size)
3
The size is the number of elements, not the last index. Because indexing starts at 0, an array of size 3 has indices 0, 1 and 2.
Reaching the end of an array
The last valid index is always size - 1. Writing it that way means the code keeps working when the array has a different length, because you never type the number 2 or 3 yourself:
val ourArray = intArrayOf(50, 40, 30)
println(ourArray[ourArray.size - 1])
println(ourArray[ourArray.size - 2])
30
40
Subtracting 1 gives the last element, subtracting 2 gives the one before it, and so on. Kotlin also has shortcuts: ourArray.last() returns the last element and ourArray.lastIndex returns size - 1. The lesson practises the explicit form, because it shows how indexes and sizes relate.
Size versus last index
The two numbers are close but different, and mixing them up is the most common array bug. The size counts elements: 4 for the ages in this lesson. The last index is one less, 3. The first index is always 0, so an array of size n has valid indices 0 up to n - 1, which is exactly n values.
The size is also the number of times a loop over the whole array runs. If you remember that rule, "size" and "last index" stay apart.
The exercise
The starter code:
val fruits = arrayOf("mango", "kiwi", "grapefruit")
val ages = intArrayOf(14, 32, 50, 21)
- Print the number of fruits.
fruits.sizeis 3, so this prints3. - Print the last age. With four ages, the last index is
ages.size - 1, which is 3. It prints21. - Print the second to last age. Subtract one more:
ages.size - 2is index 2, so it prints50.
val fruits = arrayOf("mango", "kiwi", "grapefruit")
val ages = intArrayOf(14, 32, 50, 21)
println(fruits.size)
println(ages[ages.size - 1])
println(ages[ages.size - 2])
3
21
50
Why use the size instead of a number
If the array grows to five elements when you edit the program, ages[ages.size - 1] still reads the last one, while ages[3] silently reads the fourth. Code that asks the array for its size has one fewer place to update when the data changes, and one fewer way to go wrong.
Common mistakes
- Using the size as the index.
ages[ages.size]is one past the end and throwsArrayIndexOutOfBoundsException. - Adding parentheses.
fruits.size()doesn't compile in Kotlin. Other languages use methods for this, but Kotlin arrays exposesizeas a property. - Using
length. Arrays have nolengthproperty in Kotlin. The name issize. - Trusting a fixed number.
ages[3]works only while the array has four elements.ages[ages.size - 1]is the last element for any non-empty array. - Empty arrays. For an empty array,
size - 1is -1, which isn't a valid index. Check thatsizeis above 0 before reading the last element.
Using the size in a loop
The size is what keeps loops correct when the array changes. A loop that visits every index runs from 0 up to, but not including, size:
val ages = intArrayOf(14, 32, 50, 21)
var total = 0
for (i in 0 until ages.size) {
total += ages[i]
}
println(total)
println(ages.sum())
117
117
The range 0 until ages.size excludes its end, so the last value of i is size - 1. Writing 0..ages.size would include the size itself and fail on the last pass. The library function sum() does the same job in one call, and ages.indices is another way to write the range.
The size never changes
The size of an array is set at creation. Assigning to elements doesn't change it, and there is nothing like add or removeAt for an array. Even an array with no elements is valid: IntArray(0).size is 0, and it has no valid index at all.
Key takeaways
array.sizeis the number of elements, with no parentheses.- Valid indices run from 0 to
size - 1. array[array.size - n]reaches the n-th element from the end.