[Kotlin] Basics

Variables

1
2
3
4
5
6
// readonly variable
val name: String = "Nate"

// mutable variable
var name2: String = "Tom"
name2 = ""

Types in Kotlin are by default non-nullable

1
2
// Create a nullable string
var name: String? = null

Type declaration can be omitted in Kotlin

1
2
var name = "Nate"
name = null // this won't work

Flow control

when statement behaves similar to switch

1
2
3
4
5
6
7
when(name) {
null -> println("Hi")
else -> println(name)
}

val nameToPrint = if(name != null) name else "Hi"
print(nameToPrint)

Basic Functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fun getGreeting(): String {
return "Hello World"
}
// single expression function
fun getGreeting() = "Hello World"

fun sayHello(): Unit { // Unit is a type similar to void, can be omitted here
println(getGreeting())
}

fun sayHello(itemToGreet: String) {
val msg = "Hello " + itemToGreet

// string templates
val msg = "Hello $itemToGreet"
println(msg)
}

fun sayHello(itemToGreet: String, greeting: String) = println("$greeting $itemToGreet")

Function parameters and spread operator

1
2
3
4
5
6
7
8
9
10
fun sayHello(greeting: String, vararg itemsToGreet: String) {
// vararg will be treated as an array of parameters, which can be omited(empty array)
}

sayHello("hello")
sayHello("A", "b", "c") // works too

// using spread operator to pass in array parameter
val arr = arrayOf("a", "b", "c")
sayHello("hello", *arr)

Named arguments and default arguments.

Once an argument is named, other arguments should also be named

1
2
3
4
5
6
7
fun greetPerson(greeting: String = "Hello", name: String = "Kotlin") = println("$greeting $name")

fun main() {
greetPerson()
greetPerson(greeting = "Hi")
greetPerson(name = "Nate", greeting = "Hi")
}

Iteration

Array, List, and Map

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
// array type can be inferred from the input
val arr = arrayOf("Kotlin", "Programming", "Comic Books")

println(arr.size)
println(arr[0])
println(arr.get(0))

for (item in arr) {
println(item)
}

arr.forEach {
println(it) // it is the default name for each item of the array
}

arr.forEach { item ->
println(item)
}

arr.forEachIndexed { index, item ->
println("$item is at index $index")
}

// list (more like linked list)
// list is immutable by default
val lst = listOf("Kotlin", "Programming", "Comic Books")
lst.forEach { item ->
println(item)
}

val mutableList = mutableListOf("Kotlin")
mutableList.add("Dogs")

// map is immutable by default
val map = mapOf(1 to "a", 2 to "b", 3 to "c")
map.forEach { key, value -> println("$key -> $value") }

val mutableMap = mutableMapOf(1 to "a", 2 to "b", 3 to "c")
mutableMap.put(4, "d")

Classes

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
class Person (_firstName: String, _lastName: String) {
val firstName: String
val lastName: String = _lastName

init {
// run anytime an instance of this class is run
firstName = _firstName // same as initializing out of init()
}
}

// simplify with Primary Construtor initialization
class Person (val firstName: String, val lastName: String ) {

var nickName: String? = null
set(value) {
// will be called whenever nickName is modified
field = value
println("the new nickname is $value")
}

// override the default getter
get() {
// will be called whenever the getter is called
return field
}

init {
println("init1")
}
// secondary constructor would be called if the primary constructor doesn't have any default value or value passed in
constructor(): this("Peter", "Parker") {
println("secondary constructor")
}
init { // multiple init can happen, they'll be called sequentially
println("init2")
}

// class method
fun printInfo() {
val nickNameToPrint = nickName ?: "No nickname" // if nickName is null assign the value
println("$firstName $nickNameToPrint $lastName")
}
}

fun main() {
val person = Person()
println(person.firstName) // doesn't need a getter
person.nickName = "Shades"
person.printInfo()
}