So let's start where we always start, with a hello world application:
fun main() {
println("Hello world!")
}
A couple of things to note here:
- Just like in Java, the entry point into the code is with the main method
- But unlike Java, the main method doesn't need to be in a class
- It's also not necessary to specify the args parameter, though you can if you need it, like this:
fun main(args: Array<String>) {
println("Hello world!")
}
Some other important points to note:
- Functions are defined using the fun keyword
- Parameters are defined by first specifying the name, followed by a colon and the type
Other important points for functions:
- You specify the return type using a colon and a type at the end of the function
fun main() {
println(greeting())
}
fun greeting(): String {
return "Hello world!"
}
- For functions that are a single line, you can also use expression bodies
fun main() {
println(greeting())
}
fun greeting(): String =
"Hello world!"
- And for functions that do use an expression body, you can let it infer the return type
fun main() {
println(greeting())
}
fun greeting() =
"Hello world!"
- You can also create parameters with default values
fun main() {
println(greeting())
}
fun greeting(
greeting: String = "Hello",
name: String = "world"
) = "$greeting $name!"
- And you can choose which parameters you want to provide via named arguments
fun main() {
println(greeting(name = "Bob"))
}
fun greeting(
greeting: String = "Hello",
name: String = "world"
) = "$greeting $name!"
- You can have a vararg parameter using the vararg keyword
fun main() {
println(greeting("Hi", "Bob", "Sue"))
}
fun greeting(
greeting: String = "Hello",
vararg names: String = arrayOf("world")
) = "$greeting ${names.joinToString(" and ")}!"
- Also if you want to pass an array into the vararg parameter, you need to explicitly use the spread operator
fun main() {
val names = arrayOf("Bob", "Sue")
println(greeting("Hi", *names))
}
fun greeting(
greeting: String = "Hello",
vararg names: String = arrayOf("world")
) = "$greeting ${names.joinToString(" and ")}!"
So with that, let's move on to variables:
- The difference between val and var is that val can only be assigned to once, whereas var allows reassignment
fun main() {
val myVal = "Test 1"
myVal = "Test 2" //This line breaks
var myVar = "Test 1"
myVar = "Test 2" //This works fine
}
- Kotlin is a statically typed language, but it is able to infer the type if it's being immediately assigned a value
- If the value isn't immediately specified, then a type must be specified at declaration
fun main() {
val myVal: String
myVal = "Test 1"
}
- Also note that the type cannot be changed
fun main() {
var myVar = "Test 1"
myVar = 2 //This is not allowed
}
- All types in Kotlin come in nullable and non null variants
- Non null types cannot be null
fun main() {
val myVal: String = null // This is not allowed
}
- You make a type nullable by adding a ?
fun main() {
val myVal: String? = null // This works fine
}
- You can't do anything with a nullable type until you've null checked it
fun main() {
val greeting: String? = "Hello world!"
greeting.substring(1, 3) // This doesn't compile
if (greeting != null) {
greeting.substring(1, 3) //This works fine
}
}
- There are operators that help to make null checks easier, such as the safe call operator
fun main() {
val greeting: String? = "Hello world!"
greeting?.substring(1, 3)
}
fun main() {
val greeting: String? = "Hello world!"
(greeting ?: "Some default").substring(1, 3)
}
Strings
- You can insert a variable into a string template using the $ followed by the variable name
fun main() {
println(greeting(name = "Bob"))
}
fun greeting(
greeting: String = "Hello",
name: String = "world"
) = "$greeting $name!"
- And you can insert logic using the $ by sticking it inside {}
fun main() {
println(greeting("Hi", "Bob", "Sue"))
}
fun greeting(
greeting: String = "Hello",
vararg names: String = arrayOf("world")
) = "$greeting ${names.joinToString(" and ")}!"
- We can also create multi-line strings
fun main() {
val insert = "Some insert"
val str1 = """
|I'm
| a multi-line
| string
| with indentation and and and insert: $insert
""".trimMargin()
println(str1)
}
If statements
- The major difference between if statements in Java and Kotlin is that in Kotlin an if statement can return a value
fun main() {
val result = if (1 > 2) {
"Not happening"
} else {
"Here's the result"
}
println(result)
}
When statements
- When statements are essentially a much more powerful switch statement
fun main() {
val myVal: Any = "My Test"
when (myVal) {
is String -> println(myVal.substring(3))
is Int -> println(myVal + 5)
else -> println("Unknown")
}
val myOtherVal = "Test 2"
val result = when (myOtherVal) {
"Test 1" -> "Result 1"
"Test 2" -> "Result 2"
else -> "Other"
}
println(result)
val result2 = when {
myOtherVal == myVal -> "Equal"
myOtherVal.startsWith("Test") -> "Test"
else -> "Other"
}
println(result2)
}
While loops
- While and do-while loops function the same way as they do in Java
For each loops
- For loops don't exist in Kotlin, you instead do everything with for each loops
fun main() {
for (i in 1..5) {
print("$i ")
}
println()
for (i in 1 until 5) {
print("$i ")
}
println()
for (i in 5 downTo 1) {
print("$i ")
}
println()
for (i in 1..5 step 2) {
print("$i ")
}
println()
println()
val list = listOf("One", "Two", "Three")
for (i in 0 until list.size) {
println("$i: ${list[i]}")
}
println()
for (i in list.indices) {
println("$i: ${list[i]}")
}
println()
for (item in list) {
println(item)
}
println()
}
Object destructuring
- You can use object destructuring to directly access the properties on a object
fun main() {
val map = mapOf("key1" to "value1", "key2" to "value2")
for (pair in map) {
println("${pair.key} ${pair.value}")
}
println()
for ((key, value) in map) {
println("$key, $value")
}
println()
}
- You can also use the underscore to omit properties that you don't care about
fun main() {
val map = mapOf("key1" to "value1", "key2" to "value2")
for ((key, _) in map) {
println(key)
}
println()
}
Equality
- The == in Kotlin is equivalent to the .equals call in Java
- If you need Java's == functionality, in Kotlin you use ===
Try, catch, finally
- This works similar to how it works in Java, but you can return a value from it
fun main() {
val myVal = "Hello world"
val result = try {
myVal.toInt()
} catch (e: Exception) {
0
}
println(result)
}