Kotlin Fundamentals
Master Kotlin programming with visual diagrams, data flow charts, code examples covering null safety, coroutines, collections, OOP, and best practices
Kotlin is a modern, statically-typed programming language developed by JetBrains that runs on the JVM, officially supported for Android development and backend services.
Kotlin Compilation Architecture
flowchart TB
A[Kotlin Source .kt] --> B[Kotlin Compiler]
B --> C[JVM Bytecode .class]
C --> D[Java Virtual Machine]
D --> E[Native Execution]
F[Java Interop] --> G[Call Java from Kotlin]
F --> H[Call Kotlin from Java]
I[Target Platforms] --> J[JVM]
I --> K[Android]
I --> L[JavaScript]
I --> M[Native]
style A fill:#2196F3
style B fill:#4CAF50
style C fill:#FF9800
style D fill:#9C27B0
Key Points:
- JVM Compatibility: Compiles to Java bytecode, runs on any JVM
- 100% Java Interop: Seamlessly call Java libraries and vice versa
- Multiplatform: Target JVM, Android, JavaScript, and native platforms
- Static Typing: Type safety with type inference for cleaner code
- Modern Features: Null safety, coroutines, extension functions built-in
Null Safety System
graph TB
A[Kotlin Type System] --> B[Non-Nullable Types]
A --> C[Nullable Types]
B --> B1["String - Cannot be null"]
B --> B2[Compile-time Safety]
C --> C1["String? - Can be null"]
C --> C2[Requires Null Checks]
D[Null Operators] --> E["?. Safe Call"]
D --> F["?: Elvis Operator"]
D --> G["!! Not-null Assertion"]
E --> E1[Returns null if null]
F --> F1[Provides default value]
G --> G1[Throws NPE - Avoid]
style A fill:#2196F3
style B fill:#4CAF50
style C fill:#FF9800
style D fill:#9C27B0
Key Points:
- Non-Nullable by Default: Variables cannot be null unless explicitly marked with ?
- Safe Call (?.): Returns null if receiver is null, prevents NPE
- Elvis Operator (?:): Provides default value when expression is null
- Compile-Time Safety: Most null pointer errors caught before runtime
- Smart Casts: Compiler automatically casts after null checks
Variable Declaration Types
flowchart LR
A[Variable Types] --> B[val - Immutable]
A --> C[var - Mutable]
B --> B1[Read-only Reference]
B --> B2[Like Java final]
B --> B3[Preferred Choice]
C --> C1[Reassignable]
C --> C2[Use When Needed]
D[Type Inference] --> E[Automatic Type Detection]
D --> F[Explicit Type Optional]
style A fill:#2196F3
style B fill:#4CAF50
style C fill:#FF9800
style D fill:#9C27B0
Key Points:
- val (Value): Immutable reference, cannot be reassigned after initialization
- var (Variable): Mutable reference, can be reassigned
- Type Inference: Compiler infers types from assigned values
- Best Practice: Prefer val for immutability and thread safety
Data Class Features
graph TB
A[Data Class] --> B[Auto-Generated Methods]
B --> C[equals and hashCode]
B --> D[toString]
B --> E[copy]
B --> F[componentN]
C --> C1[Value Equality]
D --> D1[String Representation]
E --> E1[Create Modified Copy]
F --> F1[Destructuring]
G[Use Cases] --> H[DTOs]
G --> I[Models]
G --> J[Value Objects]
style A fill:#2196F3
style B fill:#4CAF50
style G fill:#FF9800
Key Points:
- Automatic Generation: Compiler creates equals, hashCode, toString, copy methods
- Immutability: Encourages immutable data structures with copy() function
- Destructuring: Extract properties into variables with componentN functions
- Concise: Reduces boilerplate compared to Java POJOs
Coroutines Architecture
sequenceDiagram
participant Main as Main Thread
participant Scope as Coroutine Scope
participant Dispatcher
participant Coroutine
Main->>Scope: launch coroutine
Scope->>Dispatcher: Select dispatcher
Dispatcher->>Coroutine: Execute on thread
Coroutine->>Coroutine: suspend function
Note over Coroutine: Thread released
Coroutine->>Coroutine: Resume execution
Coroutine->>Main: Return result
Key Points:
- Lightweight Threads: Can run thousands of coroutines on few threads
- Suspend Functions: Pause execution without blocking threads
- Structured Concurrency: Automatic cancellation and error handling
- Dispatchers: Main (UI), IO (network/disk), Default (CPU-intensive)
- Non-Blocking: Efficient resource usage compared to traditional threads
Collection Operations Flow
flowchart LR
A[Collection] --> B[Transformation]
B --> C[map]
B --> D[filter]
B --> E[flatMap]
A --> F[Aggregation]
F --> G[reduce]
F --> H[fold]
F --> I[groupBy]
A --> J[Terminal]
J --> K[toList]
J --> L[first]
J --> M[count]
style A fill:#2196F3
style B fill:#4CAF50
style F fill:#FF9800
style J fill:#9C27B0
Key Points:
- Functional Operations: map, filter, reduce for data transformation
- Lazy Evaluation: Sequences for efficient processing of large collections
- Immutable by Default: Collection operations return new collections
- Extension Functions: Rich API for collection manipulation
Extension Functions Pattern
graph TB
A[Extension Functions] --> B[Add Methods to Classes]
B --> C[Without Inheritance]
B --> D[Without Modification]
E[Syntax] --> F["fun Type.method()"]
G[Use Cases] --> H[Utility Functions]
G --> I[DSL Creation]
G --> J[API Enhancement]
K[Scope] --> L[this refers to receiver]
style A fill:#2196F3
style B fill:#4CAF50
style E fill:#FF9800
style G fill:#9C27B0
Key Points:
- Extend Existing Classes: Add functionality without modifying source code
- Receiver Type: 'this' refers to the object being extended
- Static Resolution: Resolved at compile time, not runtime polymorphism
- Common Pattern: Used extensively in Kotlin standard library
Higher-Order Functions
flowchart TB
A[Higher-Order Functions] --> B[Accept Functions]
A --> C[Return Functions]
B --> D[Lambda Parameters]
C --> E[Function Factories]
F[Common Examples] --> G[map, filter, reduce]
F --> H[let, apply, run]
F --> I[also, with]
style A fill:#2196F3
style B fill:#4CAF50
style C fill:#FF9800
style F fill:#9C27B0
Key Points:
- Functions as Parameters: Pass behavior as arguments
- Lambda Expressions: Concise syntax for anonymous functions
- Scope Functions: let, apply, run, also, with for object configuration
- Functional Programming: Enables declarative, composable code
Sealed Classes Hierarchy
graph TB
A[Sealed Class] --> B[Restricted Hierarchy]
B --> C[Subclass 1]
B --> D[Subclass 2]
B --> E[Subclass 3]
F[Benefits] --> G[Exhaustive when]
F --> H[Type Safety]
F --> I[Compile-time Checks]
J[Use Cases] --> K[State Management]
J --> L[Result Types]
J --> M[UI States]
style A fill:#2196F3
style B fill:#4CAF50
style F fill:#FF9800
style J fill:#9C27B0
Key Points:
- Restricted Inheritance: All subclasses must be in same file/package
- Exhaustive when: Compiler ensures all cases handled
- Type-Safe: Better than enums for complex state with data
- Common Pattern: Result<Success, Error> types in APIs
Object Declaration Pattern
graph LR
A[Object Keyword] --> B[Singleton]
A --> C[Companion Object]
A --> D[Object Expression]
B --> B1[Single Instance]
C --> C1[Static Members]
D --> D1[Anonymous Class]
style A fill:#2196F3
style B fill:#4CAF50
style C fill:#FF9800
style D fill:#9C27B0
Key Points:
- Singleton: object declaration creates thread-safe singleton
- Companion Object: Static-like members within classes
- Object Expression: Anonymous objects for one-time use
- Lazy Initialization: Objects created on first access
Code Examples
Basic Syntax
// Variables
val name: String = "Kotlin" // Immutable
var count = 0 // Mutable, type inferred
// Null safety
val nullable: String? = null
val length = nullable?.length ?: 0
// Data class
data class User(val id: Long, val name: String)
val user = User(1, "John")
val updated = user.copy(name = "Jane")
Functions
// Basic function
fun greet(name: String): String {
return "Hello, $name"
}
// Extension function
fun String.isPalindrome() = this == this.reversed()
// Lambda
val sum = { a: Int, b: Int -> a + b }
Coroutines
// Launch coroutine
GlobalScope.launch {
val data = fetchData() // suspend function
updateUI(data)
}
// Async/await
val result = async { computeValue() }.await()