Kotlin
Kotlin is a cross-platform, statically typed, general-purpose high-level programming language with type inference. Kotlin is designed to interoperate fully with Java.
Basics
var
and val
The difference between var
and val
is that variables declared with the var
keyword can be changed/modified, while val
variables cannot.
Variable Type
Unlike many other programming languages, variables in Kotlin do not need to be declared with a specified type (like “String” for text or “Int” for numbers).
1
2
var name = "John"
val birthyear = 1975
However, it is possible to specify the type:
1
2
var name: String = "John"
val birthyear: Int = 1975
Type Conversion
Type conversion is when you convert the value of one data type to another type. To convert a numeric data type to another type, you must use one of the following functions: toByte()
, toShort()
, toInt()
, toLong()
, toFloat()
, toDouble()
or toChar()
Example
1
2
val x: Int = 5
val y: Long = x.toLong()
Standard Input
1
2
var input = readLine()
print("You entered: $input")
String
A String in Kotlin is an object, which contain properties and functions that can perform certain operations on strings, by writing a dot character (.) after the specific string variable.
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
fun main() {
val str = "Hello, Kotlin!"
// Length
println("Length: ${str.length}") // 13
// Access characters
println("Char at 1: ${str[1]}") // e
// Case conversion
println("Lowercase: ${str.lowercase()}") // hello, kotlin!
println("Uppercase: ${str.uppercase()}") // HELLO, KOTLIN!
// Trim
val spaced = " Kotlin "
println("Trim: '${spaced.trim()}'")
println("Trim Start: '${spaced.trimStart()}'")
println("Trim End: '${spaced.trimEnd()}'")
// Substring
println("Substring from 7: ${str.substring(7)}") // Kotlin!
println("Substring 0-5: ${str.substring(0, 5)}") // Hello
// Contains
println("Contains 'Kot': ${str.contains("Kot")}") // true
// StartsWith / EndsWith
println("Starts with 'Hel': ${str.startsWith("Hel")}") // true
println("Ends with '!': ${str.endsWith("!")}") // true
// IndexOf / LastIndexOf
println("Index of 'o': ${str.indexOf('o')}") // 4
println("Last index of 'o': ${str.lastIndexOf('o')}") // 9
// Replace / ReplaceFirst
println("Replace: ${str.replace("Kotlin", "World")}") // Hello, World!
println("Replace First: ${"one one one".replaceFirst("one", "1")}") // 1 one one
// Split
val parts = "a,b,c".split(",")
println("Split: $parts") // [a, b, c]
// JoinToString
val list = listOf("a", "b", "c")
println("JoinToString: ${list.joinToString(",")}") // a,b,c
// Repeat
println("Repeat: ${"Hi ".repeat(3)}") // Hi Hi Hi
// Reverse
println("Reversed: ${"abc".reversed()}") // cba
// isEmpty / isNotEmpty
println("Is empty: ${"".isEmpty()}") // true
println("Is not empty: ${"abc".isNotEmpty()}") // true
// isBlank / isNotBlank
println("Is blank: ${" ".isBlank()}") // true
println("Is not blank: ${" abc".isNotBlank()}") // true
// compareTo
println("CompareTo: ${"apple".compareTo("banana")}") // < 0
// plus
println("Plus: ${"Kotlin" + "Lang"}") // KotlinLang
// padStart / padEnd
println("Pad Start: ${"42".padStart(5, '0')}") // 00042
println("Pad End: ${"42".padEnd(5, '*')}") // 42***
// removePrefix / removeSuffix
println("Remove Prefix: ${"unhappy".removePrefix("un")}") // happy
println("Remove Suffix: ${"file.txt".removeSuffix(".txt")}") // file
// drop / dropLast
println("Drop 2: ${"Kotlin".drop(2)}") // tlin
println("DropLast 2: ${"Kotlin".dropLast(2)}") // Kotl
// take / takeLast
println("Take 3: ${"Kotlin".take(3)}") // Kot
println("TakeLast 3: ${"Kotlin".takeLast(3)}") // lin
// Capitalize / Decapitalize (deprecated, use replaceFirstChar)
println("Capitalize: ${"hello".replaceFirstChar { it.uppercase() }}") // Hello
println("Decapitalize: ${"HELLO".replaceFirstChar { it.lowercase() }}") // hELLO
// Format
val name = "Tawhid"
val age = 21
println("Format: ${"My name is %s and I’m %d years old".format(name, age)}")
// toCharArray
val chars = "Kotlin".toCharArray()
println("ToCharArray: ${chars.joinToString()}") // K, o, t, l, i, n
// Regex: matches, replace with Regex
println("Matches \\d+: ${"1234".matches(Regex("\\d+"))}") // true
println("Replace digits with #: ${"abc123".replace(Regex("\\d+"), "#")}") // abc#
// Extra: also, let, run (higher-order extension functions)
"Kotlin".also { println("Also: $it") }
"Kotlin".let { println("Let: Length is ${it.length}") }
"Kotlin".run {
println("Run: First letter is ${this[0]}")
}
}
If..Else Expressions
In Kotlin, you can also use if..else statements as expressions (assign a value to a variable and return it)
Example
1
2
3
4
5
6
val time = 20
val greeting = if (time < 18) {
"Good day."
} else {
"Good evening."
}
When
Instead of writing many if..else expressions, you can use the when expression, which is much easier to read.
1
2
3
4
5
6
7
8
9
10
11
val day = 4
val result = when (day) {
1 -> "Monday"
2 -> "Tuesday"
3 -> "Wednesday"
4 -> "Thursday"
5 -> "Friday"
6 -> "Saturday"
7 -> "Sunday"
else -> "Invalid day."
}
Array
Arrays are used to store multiple values in a single variable, instead of creating separate variables for each value.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
fun main() {
// Create arrays
val nums = arrayOf(1, 2, 3, 4, 5)
val letters = arrayOf("a", "b", "c")
// Size
println("Size: ${nums.size}") // 5
// Access and modify elements
println("First element: ${nums[0]}")
nums[0] = 10
println("Modified first element: ${nums[0]}")
// Get / Set
println("Get at 2: ${nums.get(2)}")
nums.set(2, 99)
println("Set index 2 to 99: ${nums[2]}")
// First / Last
println("First: ${nums.first()}")
println("Last: ${nums.last()}")
// IndexOf / LastIndexOf
println("Index of 99: ${nums.indexOf(99)}")
println("Last index of 99: ${nums.lastIndexOf(99)}")
// Contains / In
println("Contains 4: ${nums.contains(4)}")
println("3 in nums: ${3 in nums}") // false (we replaced 3 with 99)
// isEmpty / isNotEmpty
println("Is empty: ${nums.isEmpty()}")
println("Is not empty: ${nums.isNotEmpty()}")
// JoinToString
println("JoinToString: ${nums.joinToString()}") // 10, 2, 99, 4, 5
// forEach
nums.forEach { println("Element: $it") }
// forEachIndexed
nums.forEachIndexed { index, value -> println("Index $index: $value") }
// map
val doubled = nums.map { it * 2 }
println("Doubled: $doubled")
// filter
val even = nums.filter { it % 2 == 0 }
println("Even numbers: $even")
// any / all / none
println("Any > 10: ${nums.any { it > 10 }}")
println("All > 0: ${nums.all { it > 0 }}")
println("None < 0: ${nums.none { it < 0 }}")
// count
println("Count > 5: ${nums.count { it > 5 }}")
// find / findLast
println("Find > 10: ${nums.find { it > 10 }}")
println("FindLast > 10: ${nums.findLast { it > 10 }}")
// sum / average / max / min
println("Sum: ${nums.sum()}")
println("Average: ${nums.average()}")
println("Max: ${nums.maxOrNull()}")
println("Min: ${nums.minOrNull()}")
// take / takeLast
println("Take 3: ${nums.take(3)}")
println("TakeLast 3: ${nums.takeLast(3)}")
// drop / dropLast
println("Drop 2: ${nums.drop(2)}")
println("DropLast 2: ${nums.dropLast(2)}")
// reversed
println("Reversed: ${nums.reversed()}")
// sorted
println("Sorted: ${nums.sorted()}")
println("Sorted descending: ${nums.sortedDescending()}")
// copyOf / copyOfRange
val copied = nums.copyOf()
println("CopyOf: ${copied.joinToString()}")
val rangeCopy = nums.copyOfRange(1, 4)
println("CopyOfRange 1-4: ${rangeCopy.joinToString()}")
// fill
val filled = Array(5) { 0 }
filled.fill(7)
println("Filled with 7: ${filled.joinToString()}")
// withIndex
for ((index, value) in nums.withIndex()) {
println("WithIndex - $index: $value")
}
// toList
val list = nums.toList()
println("ToList: $list")
// contentEquals / contentDeepEquals
val arr1 = arrayOf(1, 2, 3)
val arr2 = arrayOf(1, 2, 3)
println("Content Equals: ${arr1.contentEquals(arr2)}")
// contentToString
println("ContentToString: ${arr1.contentToString()}")
// multidimensional arrays
val matrix = arrayOf(
arrayOf(1, 2),
arrayOf(3, 4)
)
println("2D Access: ${matrix[1][1]}") // 4
// contentDeepToString
println("Deep ToString: ${matrix.contentDeepToString()}")
// distinct
val dupArray = arrayOf(1, 2, 2, 3, 3, 3)
println("Distinct: ${dupArray.distinct()}") // [1, 2, 3]
// zip
val a = arrayOf(1, 2, 3)
val b = arrayOf("a", "b", "c")
val zipped = a.zip(b)
println("Zipped: $zipped") // [(1, a), (2, b), (3, c)]
// unzip
val (unzippedA, unzippedB) = zipped.unzip()
println("Unzipped A: $unzippedA")
println("Unzipped B: $unzippedB")
}
Ranges
With the for loop, you can also create ranges of values with ".."
1
2
3
for (nums in 5..15) {
println(nums)
}
The first and last value is included in the range.
Functions
A function is a block of code which only runs when it is called. You can pass data, known as parameters, into a function. Functions are used to perform certain actions, and they are also known as methods.
1
2
3
4
5
6
7
8
9
10
fun sum(x: Int, y: Int) = x + y
fun myFunction(x: Int, y: Int): Int {
return (x + y)
}
fun main() {
var result = myFunction(3, 5)
println(result) //8 (3 + 5)
}
Null Safety
Kotlin’s null safety feature helps to eliminate the risk of NullPointerException by distinguishing between nullable and non-nullable types.
- Nullable types (?)
- Safe call operator (?.)
- Elvis operator (?:)
- Not-null assertion (!!)
- let with safe calls
Examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
fun main() {
// Nullable type
val name: String? = getNameFromDatabase()
// Safe call - won't crash if name is null
println("Name length: ${name?.length}")
// Elvis operator - provides default if null
val displayName = name ?: "Guest"
println("Hello, $displayName!")
// Safe call with let
name?.let {
println("Name in uppercase: ${it.uppercase()}")
}
// Not-null assertion - throws exception if null
try {
val forcedName = name!!
println("Forced name: $forcedName")
} catch (e: KotlinNullPointerException) {
println("Caught KotlinNullPointerException: name was null!")
}
}
// This function simulates returning a nullable String
fun getNameFromDatabase(): String? {
return null // or try returning "Tawhid"
}
Explanation
- String? means it can be null.
- name?.length safely accesses length if name is not null.
- name ?: “Guest” means “use name if not null, else use ‘Guest’”.
- name?.let { … } executes the block only if name is not null.
- name!! forces access and will crash if name is null.