Skip to content

Kotlin Fundamentals

  • Kotlin is a modern, statically-typed programming language developed by JetBrains.
  • It is concise, safe, and fully interoperable with Java.

The execution of a Kotlin application begins with the main function.

fun main() {
println("Hello, Kotlin!")
}
  • fun: Keyword to declare a function.
  • main(): The name of the function, which is the program’s starting point.
  • println(): A standard library function to print a line to the console.

Variables are declared using one of two keywords: val for read-only (immutable) and var for mutable. Kotlin features type inference, meaning you usually don’t need to specify the type.

KeywordMutabilityExampleDescription
valImmutableval name = "Alice"Cannot be reassigned after initialization. Preferred for safe code.
varMutablevar count = 10Can be reassigned to a different value.

You can explicitly specify the type like this: val age: Int = 30.

Kotlin’s basic types include:

TypeExampleDescription
Intval i = 42Integers (whole numbers).
Doubleval d = 3.14Double-precision floating-point numbers.
Booleanval b = trueLogical values: true or false.
Stringval s = "text"Textual data.
Charval c = 'A'Single characters.

String Templates: You can include variable values inside a string by prefixing the variable with a dollar sign ($). For expressions, wrap them in curly braces:

val name = "World"
println("Hello, $name!") // Output: Hello, World!
val a = 5
val b = 2
println("The sum of $a and $b is ${a + b}") // Output: The sum of 5 and 2 is 7

Functions are declared using the fun keyword. The return type is placed after the parameter list, separated by a colon.

fun add(a: Int, b: Int): Int {
return a + b
}

For functions that return a single expression, you can use the assignment operator (=) and omit the body and return type (the return type is inferred).

fun multiply(x: Int, y: Int) = x * y

You can provide default values for parameters, and you can call the function using named arguments for better readability.

fun greet(name: String = "Guest", greeting: String = "Hello") {
println("$greeting, $name!")
}
// Call with default arguments:
greet() // Output: Hello, Guest!
// Call with named arguments (can be out of order):
greet(greeting = "Good morning", name = "Jane") // Output: Good morning, Jane!

Control flow statements allow your program to make decisions and repeat actions.

In Kotlin, if is an expression, meaning it returns a value. There is no ternary operator, as if can serve the same purpose.

val a = 10
val b = 20
val max = if (a > b) {
println("a is greater")
a // This is the return value of the if expression
} else {
println("b is greater or equal")
b // This is the return value of the else expression
}
println("Max value is $max") // Output: Max value is 20

The when expression replaces the traditional switch statement and is very versatile. It can be used as a statement or an expression.

fun describe(obj: Any): String =
when (obj) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long" // Check the type
!is String -> "Not a string"
else -> "Unknown"
}
println(describe(1)) // Output: One
println(describe(5L)) // Output: Long
println(describe("Hi")) // Output: Not a string

Kotlin supports for, while, and do-while loops.

LoopExampleDescription
forfor (i in 1..3) { println(i) }Iterates through anything that provides an iterator (ranges, collections, arrays).
whilevar x = 0; while (x < 5) { x++; }Executes a block of code repeatedly while a condition is true.

Ranges: You can easily create ranges of values:

  • 1..5: Inclusive range (1, 2, 3, 4, 5)
  • 1 until 5: Half-open range (1, 2, 3, 4)
  • 5 downTo 1: Reverse range
  • 1..5 step 2: Step through the range (1, 3, 5)

Kotlin’s null safety is a core feature that aims to eliminate the dreaded NullPointerException (NPE). By default, variables cannot hold a null value.

To allow a variable to hold null, you must explicitly declare its type as nullable by adding a question mark (?) at the end.

var nonNull: String = "Hello"
// nonNull = null // This would cause a compilation error
var nullable: String? = "World"
nullable = null // This is allowed

To access a property or function on a nullable variable, you must use the safe call operator (?.). It executes the operation only if the variable is non-null; otherwise, it returns null.

val length = nullable?.length // length will be Int? (nullable Int) or null

The Elvis operator provides a default value to use if the preceding expression is null.

val name: String? = null
val length = name?.length ?: 0 // If name is null, length will be 0
println(length) // Output: 0

If you are certain a nullable variable is not null, you can force the non-null type using the non-null assertion operator (!!). Use this sparingly, as it throws an NPE if the value is null.

val nonNullName: String? = "John"
val sureLength = nonNullName!!.length // Be absolutely sure nonNullName is not null!

Kotlin is an Object-Oriented Language. Classes are declared with the class keyword.

class Person(val firstName: String, var age: Int) {
// Member function (method)
fun getInfo() {
println("Name: $firstName, Age: $age")
}
}
// Creating an object (instance)
val john = Person("John", 35)
john.getInfo() // Output: Name: John, Age: 35
// Accessing properties
john.age = 36 // OK, because age is a 'var'
println(john.firstName) // OK, reading a 'val'

data class is used to create classes whose primary purpose is to hold data. The compiler automatically generates useful functions like equals(), hashCode(), toString(), and copy().

data class User(val id: Int, val name: String)
val user1 = User(1, "Alice")
val user2 = user1.copy(name = "Bob") // Creates a new object with changes
println(user1.toString()) // Output: User(id=1, name=Alice)

In Kotlin, classes are final by default (cannot be inherited). To allow inheritance, you must mark the class with the open keyword.

open class Animal(val name: String) {
open fun speak() {
println("$name makes a sound")
}
}
class Dog(name: String) : Animal(name) {
override fun speak() {
println("$name barks")
}
}
val dog = Dog("Buddy")
dog.speak() // Output: Buddy barks

Kotlin provides an extensive collection library, differentiating between immutable (read-only) and mutable collections.

Collection TypeCreation (Immutable)Creation (Mutable)Description
ListlistOf(1, 2, 3)mutableListOf(1, 2)Ordered collection of items (can contain duplicates).
SetsetOf("a", "b", "a")mutableSetOf("a", "b")Unique, unordered collection of items.
MapmapOf("k1" to 1)mutableMapOf("k2" to 2)A collection of key-value pairs (keys are unique).
// Immutable List
val numbers = listOf(1, 2, 3, 4)
// numbers.add(5) // ERROR!
// Mutable List
val mutableNumbers = mutableListOf(10, 20)
mutableNumbers.add(30) // OK
println(mutableNumbers) // Output: [10, 20, 30]