Kotlin โ Complete Beginner Tutorial
6 modules ยท 12 examples ยท Click โถ Run โ See Output to see exact console output
Variables & Data Types
Every program needs to store data. In Kotlin, you use val to store a value that will never change, and var to store a value you might update later. Kotlin can figure out the type automatically from the value you give it โ this is called type inference. But you can also be explicit and write the type yourself.
val and var โ the two types of variables
val is short for 'value' โ once you set it, you cannot change it. var is short for 'variable' โ you can change it whenever you want. Use val as much as possible โ it makes your code safer and more predictable. Only use var when you genuinely need to update the value.
๐ Teaches: val, var, type inference, basic data types
1"color:#7F52FF">fun main() {2 "color:#6b7280">// "color:#7F52FF">val = cannot be changed (immutable)3 "color:#7F52FF">val name = "Alice"4 "color:#7F52FF">val country = "South Africa"56 "color:#6b7280">// "color:#7F52FF">var = can be changed (mutable)7 "color:#7F52FF">var age = 208 "color:#7F52FF">var score = 0910 "color:#7F52FF">println("Name: $name")11 "color:#7F52FF">println("Country: $country")12 "color:#7F52FF">println("Age: $age")1314 "color:#6b7280">// Update a "color:#7F52FF">var variable15 age = 2116 score = 10017 "color:#7F52FF">println("Next year age: $age")18 "color:#7F52FF">println("Score: $score")19}
Pro tip: Kotlin can infer types automatically. Writing val name = "Alice" and val name: String = "Alice" are identical. Prefer the shorter version unless the type isn't obvious from the value.
Data Types
Kotlin has specific types for different kinds of data. Int for whole numbers, Double for decimals, Boolean for true/false, String for text, Char for a single character. Knowing the right type to use matters โ you cannot add an Int to a String without converting it.
๐ Teaches: Int, Double, Boolean, String, Char, explicit types
1"color:#7F52FF">fun main() {2 "color:#7F52FF">val age: Int = 25 "color:#6b7280">// whole number3 "color:#7F52FF">val price: Double = 9.99 "color:#6b7280">// decimal number4 "color:#7F52FF">val isStudent: Boolean = "color:#7F52FF">true5 "color:#7F52FF">val firstName: String = "Bob"6 "color:#7F52FF">val grade: Char = 'A'78 "color:#7F52FF">println("Age: $age")9 "color:#7F52FF">println("Price: R$price")10 "color:#7F52FF">println("Is student: $isStudent")11 "color:#7F52FF">println("Name: $firstName")12 "color:#7F52FF">println("Grade: $grade")1314 "color:#6b7280">// Basic arithmetic15 "color:#7F52FF">val tax = price * 0.1516 "color:#7F52FF">println("Tax: R$tax")17}
Pro tip: In Kotlin, Int.MAX_VALUE is 2,147,483,647. If you need larger numbers use Long. For very precise decimal calculations (like money), use BigDecimal instead of Double.
String Templates & Input
Strings in Kotlin are powerful. The string template feature lets you embed any variable or expression directly inside a string using the $ sign โ no need for clunky string concatenation. This makes your output code clean and readable. You can also read input from the user with readLine().
String Templates
Instead of writing 'Hello ' + name + '!' like in Java, Kotlin lets you write "Hello $name!" โ cleaner and easier to read. For expressions (calculations or method calls), wrap them in curly braces: ${expression}. This works inside any double-quoted string.
๐ Teaches: $variable, ${expression}, string concatenation alternative
1"color:#7F52FF">fun main() {2 "color:#7F52FF">val firstName = "Lebo"3 "color:#7F52FF">val lastName = "Dlamini"4 "color:#7F52FF">val age = 225 "color:#7F52FF">val score = 87.567 "color:#6b7280">// Simple variable "color:#7F52FF">in string8 "color:#7F52FF">println("Hello, $firstName!")910 "color:#6b7280">// Expression "color:#7F52FF">in string11 "color:#7F52FF">println("Full name: ${firstName + " " + lastName}")1213 "color:#6b7280">// Calculation "color:#7F52FF">in string14 "color:#7F52FF">println("Score: $score%")15 "color:#7F52FF">println("Pass: ${score >= 50}")1617 "color:#6b7280">// Multi-line with string templates18 "color:#7F52FF">val message = """19 Student: $firstName $lastName20 Age: $age21 Result: ${"color:#7F52FF">if (score >= 50) "PASS" "color:#7F52FF">else "FAIL"}22 """.trimIndent()2324 "color:#7F52FF">println(message)25}
Pro tip: The triple-quoted string ("""...""") lets you write multi-line strings without \n escape characters. Combined with .trimIndent() it strips the leading spaces from each line.
Reading User Input
readLine() reads a line of text the user types. It always returns a String? (nullable String โ it could be null). Use ?: to provide a fallback if it is null. To convert the input to a number, use .toInt() or .toDouble(). This is how you make interactive programs.
๐ Teaches: readLine(), ?: operator, toInt(), toDouble(), nullable types
1"color:#7F52FF">fun main() {2 "color:#7F52FF">print("Enter your name: ")3 "color:#7F52FF">val name = readLine() ?: "Unknown"45 "color:#7F52FF">print("Enter your age: ")6 "color:#7F52FF">val ageText = readLine() ?: "0"7 "color:#7F52FF">val age = ageText.toInt()89 "color:#7F52FF">println("Hello, $name!")10 "color:#7F52FF">println("In 10 years you will be ${age + 10} years old.")1112 "color:#6b7280">// Check the input13 "color:#7F52FF">if (age >= 18) {14 "color:#7F52FF">println("You are an adult.")15 } "color:#7F52FF">else {16 "color:#7F52FF">println("You are a minor.")17 }18}
Pro tip: readLine() returns String? (nullable). The ?: operator is called the Elvis operator โ it returns the left value if not null, or the right value if null. val name = readLine() ?: "Guest" means: use the input, or "Guest" if the input is null.
Control Flow
Control flow determines the order your code runs. With if/else, your code makes decisions. With for and while loops, it repeats actions. Kotlin's when expression is an elegant replacement for Java's switch statement. One key advantage: in Kotlin, if and when are expressions โ they return a value, so you can assign them to a variable.
if / else and when
The if statement runs code only when a condition is true. The when expression checks a value against multiple options โ much cleaner than a chain of if/else if. Both can return a value, making them very flexible in Kotlin.
๐ Teaches: if, else if, else, when expression, comparison operators
1"color:#7F52FF">fun main() {2 "color:#7F52FF">val score = 7834 "color:#6b7280">// Standard "color:#7F52FF">if / "color:#7F52FF">else5 "color:#7F52FF">val grade = "color:#7F52FF">if (score >= 90) "A"6 "color:#7F52FF">else "color:#7F52FF">if (score >= 75) "B"7 "color:#7F52FF">else "color:#7F52FF">if (score >= 60) "C"8 "color:#7F52FF">else "F"910 "color:#7F52FF">println("Score: $score Grade: $grade")1112 "color:#6b7280">// "color:#7F52FF">when expression13 "color:#7F52FF">val day = 314 "color:#7F52FF">val dayName = "color:#7F52FF">when (day) {15 1 -> "Monday"16 2 -> "Tuesday"17 3 -> "Wednesday"18 4 -> "Thursday"19 5 -> "Friday"20 "color:#7F52FF">else -> "Weekend"21 }2223 "color:#7F52FF">println("Day $day ">is $dayName")2425 "color:#6b7280">// "color:#7F52FF">when with ranges26 "color:#7F52FF">val temp = 2227 "color:#7F52FF">val weather = "color:#7F52FF">when {28 temp < 10 -> "Very cold"29 temp < 20 -> "Cool"30 temp < 30 -> "Warm"31 "color:#7F52FF">else -> "Hot"32 }33 "color:#7F52FF">println("$tempยฐC โ $weather")34}
Pro tip: when without an argument (just when { ... }) works like a series of if/else if conditions. Each branch can check any boolean expression. This is much cleaner than chaining many if/else if blocks.
for and while Loops
Loops repeat a block of code. The for loop is perfect when you know how many times to repeat โ use a range like 1..5 or loop over a collection. The while loop keeps running as long as a condition is true โ useful when you don't know in advance how many repeats you need.
๐ Teaches: for loop, ranges (1..n), downTo, step, while loop
1"color:#7F52FF">fun main() {2 "color:#6b7280">// "color:#7F52FF">for loop with range3 "color:#7F52FF">println("Counting up:")4 "color:#7F52FF">for (i "color:#7F52FF">in 1..5) {5 "color:#7F52FF">print("$i ")6 }7 "color:#7F52FF">println()89 "color:#6b7280">// Count down10 "color:#7F52FF">println("Counting down:")11 "color:#7F52FF">for (i "color:#7F52FF">in 5 downTo 1) {12 "color:#7F52FF">print("$i ")13 }14 "color:#7F52FF">println()1516 "color:#6b7280">// Skip every other number17 "color:#7F52FF">println("Even numbers:")18 "color:#7F52FF">for (i "color:#7F52FF">in 2..10 step 2) {19 "color:#7F52FF">print("$i ")20 }21 "color:#7F52FF">println()2223 "color:#6b7280">// "color:#7F52FF">while loop24 "color:#7F52FF">println("While loop:")25 "color:#7F52FF">var count = 126 "color:#7F52FF">while (count <= 3) {27 "color:#7F52FF">println(" Loop $count")28 count++29 }30}
Pro tip: 1..5 creates a range from 1 to 5 inclusive. 1 until 5 creates a range from 1 to 4 (excludes the end). Use downTo to count backwards and step to skip numbers.
Functions
A function is a named block of code that does one specific job. You define it once and call it as many times as you need โ from anywhere in your program. Functions make your code organised, reusable and easy to read. Kotlin functions are very flexible โ they support default parameter values, named arguments and can be written in a single line.
Defining and Calling Functions
Use the fun keyword to define a function. You specify what parameters it takes (inputs) and what type it returns (output). If a function doesn't return anything useful, the return type is Unit (which you can omit). Call a function by writing its name followed by parentheses.
๐ Teaches: fun keyword, parameters, return types, calling functions, Unit
1"color:#6b7280">// Function that returns nothing (Unit)2"color:#7F52FF">fun greet(name: String) {3 "color:#7F52FF">println("Hello, $name!")4}56"color:#6b7280">// Function that returns a value7"color:#7F52FF">fun add(a: Int, b: Int): Int {8 "color:#7F52FF">return a + b9}1011"color:#6b7280">// Single-expression function (shorter syntax)12"color:#7F52FF">fun multiply(a: Int, b: Int) = a * b1314"color:#6b7280">// Function with default parameter15"color:#7F52FF">fun greetUser(name: String, greeting: String = "Hello") {16 "color:#7F52FF">println("$greeting, $name!")17}1819"color:#7F52FF">fun main() {20 greet("Amara")2122 "color:#7F52FF">val result = add(10, 5)23 "color:#7F52FF">println("10 + 5 = $result")2425 "color:#7F52FF">println("4 x 6 = ${multiply(4, 6)}")2627 greetUser("Thabo") "color:#6b7280">// uses default28 greetUser("Sipho", "Good morning") "color:#6b7280">// custom greeting29}
Pro tip: Single-expression functions use = instead of { return ... }. fun square(x: Int) = x * x is identical to fun square(x: Int): Int { return x * x } โ just much shorter. Use this when the whole function body is one expression.
Named Arguments & Default Values
Kotlin lets you name your arguments when calling a function. This makes calls much clearer โ you can see what each value means without looking at the function definition. You can also change the order of arguments when you name them, and skip any that have default values.
๐ Teaches: named arguments, default parameter values, argument order
1"color:#7F52FF">fun createProfile(2 name: String,3 age: Int,4 city: String = "Unknown",5 isStudent: Boolean = "color:#7F52FF">false6) {7 "color:#7F52FF">println("Name: $name")8 "color:#7F52FF">println("Age: $age")9 "color:#7F52FF">println("City: $city")10 "color:#7F52FF">println("Student: $isStudent")11 "color:#7F52FF">println("---")12}1314"color:#7F52FF">fun main() {15 "color:#6b7280">// All arguments "color:#7F52FF">by position16 createProfile("Alice", 22, "Johannesburg", "color:#7F52FF">true)1718 "color:#6b7280">// Skip optional arguments19 createProfile("Bob", 30)2021 "color:#6b7280">// Use named arguments (order doesn't matter)22 createProfile(23 age = 19,24 name = "Zanele",25 isStudent = "color:#7F52FF">true26 )27}
Pro tip: Named arguments are especially useful for Boolean parameters. createProfile(isStudent = true) is far clearer than createProfile(true) โ you can instantly see what true means without checking the function signature.
Null Safety & Classes
Null safety is what sets Kotlin apart from Java. The compiler forces you to handle null before it can crash your app. For classes, Kotlin is far more concise than Java โ a class with properties, a constructor and auto-generated toString, equals and hashCode can be defined in a single line using data class.
Null Safety โ ?, ?. and ?:
In Kotlin, a regular variable can NEVER be null. If you want a variable that might be null, add ? to the type. Then you must handle the null case before using the value โ the compiler will not let you forget. The safe call operator ?. runs the code only if the value is not null. The Elvis operator ?: provides a fallback if it is null.
๐ Teaches: nullable types (?), safe call (?.), Elvis operator (?:), null checks
1"color:#7F52FF">fun main() {2 "color:#6b7280">// Non-nullable โ cannot be "color:#7F52FF">null3 "color:#7F52FF">val name: String = "Alice"45 "color:#6b7280">// Nullable โ can be "color:#7F52FF">null6 "color:#7F52FF">var nickname: String? = "color:#7F52FF">null78 "color:#6b7280">// Safe call โ only runs "color:#7F52FF">if not "color:#7F52FF">null9 "color:#7F52FF">println(nickname?.length) "color:#6b7280">// prints: "color:#7F52FF">null (no crash)1011 nickname = "Ally"12 "color:#7F52FF">println(nickname?.length) "color:#6b7280">// prints: 41314 "color:#6b7280">// Elvis operator โ fallback "color:#7F52FF">if "color:#7F52FF">null15 "color:#7F52FF">val displayName = nickname ?: "Anonymous"16 "color:#7F52FF">println("Display: $displayName")1718 "color:#6b7280">// Real example โ checking user input19 "color:#7F52FF">val input: String? = "color:#7F52FF">null20 "color:#7F52FF">val result = input?.uppercase() ?: "No input provided"21 "color:#7F52FF">println(result)2223 "color:#6b7280">// Null check with "color:#7F52FF">if24 "color:#7F52FF">if (nickname != "color:#7F52FF">null) {25 "color:#6b7280">// Inside here, compiler knows it's not "color:#7F52FF">null26 "color:#7F52FF">println("Uppercase: ${nickname.uppercase()}")27 }28}
Pro tip: Avoid the !! (non-null assertion) operator unless you are absolutely certain the value is not null. Using !! means 'trust me, this is not null' โ if you are wrong, your app crashes with a KotlinNullPointerException.
Classes and Data Classes
A class is a blueprint for creating objects. Data classes are a Kotlin shortcut for classes that just hold data โ they automatically generate toString(), equals(), hashCode() and copy() methods. One line replaces 50+ lines of Java boilerplate.
๐ Teaches: class, data class, properties, methods, objects, copy()
1"color:#6b7280">// Regular "color:#7F52FF">class2"color:#7F52FF">class Person("color:#7F52FF">val name: String, "color:#7F52FF">var age: Int) {3 "color:#7F52FF">fun introduce() {4 "color:#7F52FF">println("Hi, I'm $name and I'm $age years old.")5 }6}78"color:#6b7280">// Data "color:#7F52FF">class โ auto-generates toString, equals, copy9"color:#7F52FF">data "color:#7F52FF">class Student(10 "color:#7F52FF">val id: Int,11 "color:#7F52FF">val name: String,12 "color:#7F52FF">val grade: String13)1415"color:#7F52FF">fun main() {16 "color:#6b7280">// Create objects17 "color:#7F52FF">val person = Person("Lebo", 25)18 person.introduce()1920 "color:#6b7280">// Update mutable property21 person.age = 2622 "color:#7F52FF">println("${person.name} ">is now ${person.age}")2324 "color:#6b7280">// Data "color:#7F52FF">class25 "color:#7F52FF">val student1 = Student(1, "Thabo", "A")26 "color:#7F52FF">println(student1) "color:#6b7280">// auto-generated toString2728 "color:#6b7280">// copy() creates a modified copy29 "color:#7F52FF">val student2 = student1.copy(id = 2, name = "Zanele")30 "color:#7F52FF">println(student2)3132 "color:#6b7280">// equals() auto-generated33 "color:#7F52FF">val student3 = Student(1, "Thabo", "A")34 "color:#7F52FF">println("Same? ${student1 == student3}")35}
Pro tip: Use data class when your class is mainly about storing data (model classes, API responses, database records). Use a regular class when your class has complex behaviour and state. In Android development, data classes are used constantly for API models.
Collections & Lambdas
Collections โ lists, sets and maps โ let you work with groups of data. Kotlin collections have two forms: read-only (listOf, mapOf) and mutable (mutableListOf, mutableMapOf). Lambdas are short, anonymous functions passed as values. Together with collection functions like filter, map and forEach, lambdas let you process data in a clean, readable way.
Lists and Common Operations
A list stores items in order. Use listOf() for a read-only list and mutableListOf() for one you can add to or remove from. You can loop through lists, access items by index, and use powerful functions like filter (keep matching items) and map (transform each item).
๐ Teaches: listOf, mutableListOf, indexing, forEach, filter, map, size
1"color:#7F52FF">fun main() {2 "color:#6b7280">// Read-only list3 "color:#7F52FF">val languages = listOf("Kotlin", "Python", "Java", "Swift")45 "color:#7F52FF">println("All languages:")6 "color:#7F52FF">for (lang "color:#7F52FF">in languages) {7 "color:#7F52FF">println(" - $lang")8 }910 "color:#7F52FF">println("Total: ${languages.size}")11 "color:#7F52FF">println("First: ${languages[0]}")12 "color:#7F52FF">println("Last: ${languages.last()}")1314 "color:#6b7280">// Filter โ keep items matching a condition15 "color:#7F52FF">val shortNames = languages.filter { it.length <= 5 }16 "color:#7F52FF">println("Short names: $shortNames")1718 "color:#6b7280">// Map โ transform each item19 "color:#7F52FF">val upperCase = languages.map { it.uppercase() }20 "color:#7F52FF">println("Uppercase: $upperCase")2122 "color:#6b7280">// Mutable list23 "color:#7F52FF">val scores = mutableListOf(85, 92, 78)24 scores.add(95)25 scores.remove(78)26 "color:#7F52FF">println("Scores: $scores")27 "color:#7F52FF">println("Average: ${scores.average()}")28}
Pro tip: The it keyword inside a lambda refers to the current element being processed. languages.filter { it.length <= 5 } reads naturally as: 'from languages, keep each item where the item's length is 5 or less.'
Maps and Practical Example
A map stores key-value pairs โ like a dictionary. You look up a value by its key. Use mapOf() for read-only maps and mutableMapOf() for maps you can modify. Maps are perfect for storing related data like a student's name and their grade.
๐ Teaches: mapOf, mutableMapOf, key-value pairs, get, containsKey, forEach on map
1"color:#7F52FF">fun main() {2 "color:#6b7280">// Map โ key/value pairs3 "color:#7F52FF">val grades = mapOf(4 "Alice" "color:#7F52FF">to "A",5 "Bob" "color:#7F52FF">to "B",6 "Carol" "color:#7F52FF">to "A",7 "Dave" "color:#7F52FF">to "C"8 )910 "color:#6b7280">// Access a value "color:#7F52FF">by key11 "color:#7F52FF">println("Alice's grade: ${grades["Alice"]}")1213 "color:#6b7280">// Safe access (returns "color:#7F52FF">null "color:#7F52FF">if key not found)14 "color:#7F52FF">val grade = grades["Eve"] ?: "Not enrolled"15 "color:#7F52FF">println("Eve's grade: $grade")1617 "color:#6b7280">// Loop through all entries18 "color:#7F52FF">println("19All grades:")20 "color:#7F52FF">for ((name, g) "color:#7F52FF">in grades) {21 "color:#7F52FF">println(" $name โ $g")22 }2324 "color:#6b7280">// Filter students with grade A25 "color:#7F52FF">val topStudents = grades.filter { it.value == "A" }26 "color:#7F52FF">println("27Top students: ${topStudents.keys}")2829 "color:#6b7280">// Mutable map30 "color:#7F52FF">val wordCount = mutableMapOf<String, Int>()31 "color:#7F52FF">val words = listOf("kotlin", "">is", "">fun", "kotlin", "">is", "great")32 "color:#7F52FF">for (word "color:#7F52FF">in words) {33 wordCount[word] = (wordCount[word] ?: 0) + 134 }35 "color:#7F52FF">println("Word count: $wordCount")36}
Pro tip: Destructuring in the for loop โ for ((name, grade) in grades) โ automatically unpacks each map entry into two separate variables. This is much cleaner than writing entry.key and entry.value.
You finished the Kotlin tutorial!
You now know variables, strings, control flow, functions, null safety, classes and collections โ the full foundation of Kotlin. Your next step is to build a real Android app using Android Studio.