No history yet

Kotlin Basics

The Building Blocks

Every program, no matter how complex, starts with data. In Kotlin, we store data in variables. Think of a variable as a labeled box where you can keep a piece of information. There are two main types of boxes: one you can change the contents of, and one you can't.

A changeable variable is declared with var. You might use this for something that needs to be updated, like a user's score in a game.

A read-only variable is declared with val. Once you put something in a val box, it stays there. This is great for things that don't change, like a person's date of birth. It's generally better to use val whenever possible because it makes your code safer and easier to understand.

Variables also have a type, which tells the system what kind of data they hold. Kotlin is smart and can usually figure this out on its own, a feature called type inference. The most common types are:

  • Int: For whole numbers, like 10 or -5.
  • Double: For numbers with decimal points, like 3.14.
  • String: For text, which is always wrapped in double quotes, like "Hello, world!".
  • Boolean: For true or false values.
// Use 'val' for a value that never changes.
val name: String = "Alex"

// Use 'var' for a variable that can be reassigned.
var score: Int = 0
score = 10 // This is okay

// Kotlin often infers the type, so you can write:
val level = 5 // Kotlin knows this is an Int
val pi = 3.14 // Kotlin knows this is a Double

Making Decisions

A program isn't very useful if it does the same thing every time. We need ways to control its flow based on certain conditions. The most basic way to do this is with an if-else statement. It's just like it sounds: if a condition is true, do something; else, do something different.

val temperature = 25

if (temperature > 20) {
    println("It's a warm day!")
} else {
    println("It's a bit chilly.")
}

When you have many possible conditions, if-else can get messy. Kotlin has a cleaner solution called when. It lets you check a variable against several possible values and run a block of code for the one that matches.

val dayOfWeek = 3

val dayName = when (dayOfWeek) {
    1 -> "Monday"
    2 -> "Tuesday"
    3 -> "Wednesday"
    4 -> "Thursday"
    5 -> "Friday"
    else -> "Weekend"
}

println(dayName) // Prints "Wednesday"

We also need ways to repeat actions. A for loop is perfect for running a piece of code for each item in a collection, like a list of names. A while loop is a bit different; it keeps running while a certain condition remains true.

// 'for' loop to iterate over a range of numbers
for (i in 1..4) {
    println("Launch sequence: $i")
}

// 'while' loop to count down
var countdown = 3
while (countdown > 0) {
    println(countdown)
    countdown = countdown - 1 // or countdown--
}
println("Liftoff!")

Packaging Your Code

As your programs grow, you'll find yourself writing the same lines of code over and over. Functions let you package up a block of code, give it a name, and reuse it whenever you need it. A function can take in data (called parameters) and can also return a result.

// A simple function that takes two integers and returns their sum
fun add(a: Int, b: Int): Int {
    return a + b
}

// Call the function and store the result
val sum = add(5, 3)
println(sum) // Prints 8

Sometimes you need a small, unnamed function for a quick task. This is where lambda expressions come in. They are essentially functions without a name, which you can treat like a value and pass around in your code. They are especially useful when working with collections of data.

A lambda expression is always surrounded by curly braces {}.

val numbers = listOf(1, 2, 3, 4)

// Use a lambda with the forEach function
// to print each number in the list.
numbers.forEach { number ->
    println(number)
}

Blueprints for Data

Object-Oriented Programming (OOP) is a way of thinking about code that involves grouping related data and behaviors into tidy bundles called objects. The blueprint for creating an object is a class.

Imagine you're building a game with different characters. You could create a Character class that defines what every character should have, like a name and health points, and what they can do, like attack or defend.

class Character(val name: String, var health: Int) {
    fun attack() {
        println("$name attacks!")
    }
}

// Create an 'instance' (an object) from the class blueprint
val player = Character("Gandalf", 100)

// Access its properties and call its functions
println(player.name) // Prints "Gandalf"
player.attack() // Prints "Gandalf attacks!"

One of the biggest sources of crashes in many programming languages is trying to use a variable that doesn't have a value—often called a null value. Kotlin helps prevent this with its null safety system.

By default, variables in Kotlin cannot be null. If you need a variable that can be null, you have to explicitly say so by adding a question mark ? to its type.

This forces you to think about how your program should handle cases where data might be missing.

// This variable can hold a String or be null.
var middleName: String? = "B."

// This one cannot be null.
// var firstName: String = null // This line would cause an error!

// To safely use a nullable variable, use the safe call operator `?.`
// The code only runs if middleName is not null.
println(middleName?.length)

middleName = null

// Use the Elvis operator `?:` to provide a default value if it's null.
val nameLength = middleName?.length ?: 0
println(nameLength) // Prints 0

Let's review these core concepts.

Ready to check your understanding?

Quiz Questions 1/6

In Kotlin, you are writing a program to store a user's date of birth. This value will be set once and will never change. Which keyword is most appropriate for declaring the variable?

Quiz Questions 2/6

It is generally considered a best practice in Kotlin to prefer var over val.

These building blocks are the foundation for everything you'll do in Kotlin. Mastering them will prepare you to build powerful and reliable Android apps.