Type Checking at Compile-Time, immutable, mutable:
val name = "range" // Immutable var age = 30 // Mutable var count: Int = 10
Late Initialisation or null(var only):
lateinit var description: String
fun setup(){
description = "haha"
}
var name:String? = null
safe call:
// ?. must always be placed between an object and a member access (like .). // It is not a standalone null-check operator. // Often combined with the Elvis operator (?:) to provide a default value: val len = user.name?.length ?: 0
not-null assertion operator
// !! // If the value is not null, execution continues normally. // If the value is null, a NullPointerException (NPE) is thrown at runtime. val name: String? = null val len = name!!.length // NullPointerException
Function definition
fun functionName(param1: Type1, param2: Type2): ReturnType {
// body
return value
}
// you may use Unit to replace the ReturnType. This means there is no return value
// or you can write in this form is this is a one-line-func
fun square(x: Int): Int = x * x
// Default Arguments
fun greet(name: String = "Guest") {
println("Hello, $name")
}
// Named Arguments (para passing)
fun register(name: String, age: Int, email: String) { }
register(age = 20, name = "Tom", email = "[email protected]")
// Vararg
fun sum(vararg numbers: Int): Int {
return numbers.sum()
}
val total = sum(1, 2, 3, 4) // 10
control flow
// when, a better switch
when (x) {
1 -> println("One")
in 2..5 -> println("Between 2 and 5")
is String -> println("It’s a String")
else -> println("Other")
}
// for
for (i in 1..5) println(i) // 1 2 3 4 5
for (i in 10 downTo 1 step 3) print("$i ") // 10 7 4 1
for (item in listOf("a","b")) println(item)
// while
var i = 3
while (i > 0) {
println(i)
i--
}
// do...while
var i = 0
do {
println(i)
i++
} while (i < 3)
class
// =========================
// 1. Class Declaration
// =========================
class Person {
var name: String = "Unknown" // mutable property
fun sayHello() = println("Hello, I’m $name") // simple member function
}
// =========================
// 2. Primary Constructor + init block
// =========================
// Kotlin allows declaring a "primary constructor" directly in the class header.
// It is concise and good for classes whose main purpose is to hold state.
// The 'init' block is used for additional initialization logic.
class User(val name: String, var age: Int) {
init {
println("User created: $name, age: $age")
}
}
// =========================
// 3. Secondary Constructor
// =========================
// Why does Kotlin have both primary and secondary constructors?
// - Primary constructor: concise, defines essential properties upfront.
// - Secondary constructor: allows flexibility and multiple ways of constructing the same class.
// Useful for backward compatibility or alternative initialization logic.
class Student {
var name: String
var grade: Int
constructor(name: String, grade: Int) { // secondary constructor
this.name = name
this.grade = grade
}
}
// =========================
// 4. Data Class
// =========================
// Data classes are special: they automatically generate
// equals(), hashCode(), toString(), copy(), and componentN() for destructuring.
data class Book(val title: String, val price: Double)
// =========================
// 5. Inheritance
// =========================
// By default, Kotlin classes are 'final' (cannot be inherited).
// We must mark them 'open' to allow inheritance.
open class Animal {
open fun sound() = println("Some sound")
}
class Dog : Animal() {
override fun sound() = println("Woof!") // explicit 'override' is required
}
// =========================
// 6. Interface
// =========================
// Interfaces can contain both abstract methods and methods with default implementation.
interface Drivable {
fun drive() // abstract
fun stop() = println("Stopped") // default implementation
}
class Car : Drivable {
override fun drive() = println("Car is driving")
}
// =========================
// 7. Abstract Class
// =========================
// Abstract classes cannot be instantiated.
// They may contain abstract members (must be implemented) and concrete ones.
abstract class Shape {
abstract fun area(): Double
fun describe() = println("I am a shape") // concrete method
}
class Circle(val r: Double) : Shape() {
override fun area() = Math.PI * r * r
}
// =========================
// (No need for main() here)
// The above code demonstrates:
// - simple class declaration
// - primary vs secondary constructors
// - data classes
// - inheritance rules
// - interfaces
// - abstract classes
// =========================
lambda
// =========================
// Kotlin Lambda Expressions
// =========================
// 1. Basic Lambda Expression
// A lambda is an anonymous function (function without a name).
// Syntax: { parameter(s) -> body }
val square = { x: Int -> x * x }
// Usage: square(5) -> 25
// 2. Lambda with multiple parameters
val add = { a: Int, b: Int -> a + b }
// Usage: add(2, 3) -> 5
// 3. Type inference
// If the context provides enough type information, you can omit parameter types.
val multiply: (Int, Int) -> Int = { a, b -> a * b }
// 4. Single parameter shortcut ('it')
// If there is only one parameter, you can omit its name and use 'it'.
val doubled = { x: Int -> x * 2 }
val doubled2: (Int) -> Int = { it * 2 }
// 5. Lambda as function argument
// Many Kotlin library functions (map, filter, forEach) take lambdas as arguments.
val numbers = listOf(1, 2, 3, 4)
val squares = numbers.map { it * it } // [1, 4, 9, 16]
val evens = numbers.filter { it % 2 == 0 } // [2, 4]
// 6. Lambda with 'return'
// 'return' inside a lambda returns from the nearest function that takes the lambda.
// Often replaced with functions like 'forEach' or 'map' to avoid explicit loops.
fun process(nums: List<Int>) {
nums.forEach {
if (it < 0) return // exits the entire process() function, not just the lambda
println(it)
}
}
// 7. Higher-order function
// A function that takes a lambda (function) as a parameter.
fun operateOnTwoNumbers(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
// Example usage:
// operateOnTwoNumbers(3, 4, { x, y -> x + y }) // 7
// With Kotlin's lambda syntax sugar, we can write:
// operateOnTwoNumbers(3, 4) { x, y -> x + y } // cleaner
// 8. Trailing Lambda Syntax
// If the last parameter of a function is a lambda, it can be placed outside the parentheses.
val result = numbers.fold(0) { acc, n -> acc + n } // sum of list
Views: 10