Variables & Types
The val/var model, type inference, Kotlin's type system, and type casting.
val vs var — Immutability First
Kotlin introduces a strict immutability model. Instead of overloading final everywhere, you choose val (immutable) or var (mutable) upfront:
// Immutable requires 'final'
final String name = "Alice";
// Mutable (default)
String city = "KL";
city = "Penang"; // allowed
// Final can't be reassigned
// name = "Bob"; // ❌ compile error
// val = immutable (like Java final)
val name = "Alice"
// name = "Bob" // ❌ compile error
// var = mutable
var city = "KL"
city = "Penang" // ✅ allowed
// Convention: prefer val over var
Always start with val and only switch to var when you actually need reassignment. This makes code more predictable and thread-safe.
Type Inference
Kotlin infers types from the right-hand side at compile time — this is not dynamic typing. The type is fixed, just inferred:
int count = 42;
double pi = 3.14;
String text = "hello";
boolean isActive = true;
List<String> items = new ArrayList<>();
val count = 42 // Int
val pi = 3.14 // Double
val text = "hello" // String
val isActive = true // Boolean
val items = mutableListOf<String>()
// Explicit type when needed:
val count2: Int = 42
Kotlin's Basic Types
Kotlin does not have Java's primitive/object duality. All types are objects — the compiler optimizes to JVM primitives where possible:
| Kotlin Type | Java Equivalent | Notes |
|---|---|---|
Int | int / Integer | 32-bit signed |
Long | long / Long | 64-bit signed, append L: 100L |
Double | double / Double | 64-bit float (default for decimals) |
Float | float / Float | Append f: 3.14f |
Boolean | boolean / Boolean | true / false |
Char | char / Character | Single character: 'A' |
String | String | Immutable, supports templates |
Any | Object | Root of the type hierarchy |
Unit | void | Return type for functions with no value |
Nothing | No direct equivalent | Function that never returns (throws/loops) |
Type Casting — as and is
Kotlin's type check and cast operators replace Java's instanceof and explicit casts:
Object obj = "Hello";
if (obj instanceof String) {
// Must cast manually
String s = (String) obj;
System.out.println(s.length());
}
// Unsafe cast: ClassCastException risk
String s2 = (String) obj;
val obj: Any = "Hello"
// 'is' check — like instanceof
if (obj is String) {
// Smart cast: obj IS String here!
println(obj.length) // no explicit cast
}
// Safe cast: returns null if fails
val s: String? = obj as? String
// Unsafe cast (like Java)
val s2 = obj as String // ClassCastException if fails
After an is check, Kotlin automatically smart-casts the variable to the checked type inside the if block. No redundant explicit cast needed — unlike Java's instanceof pattern.
Multi-line Strings
"""val json = """
{
"name": "Alice",
"age": 30
}
""".trimIndent()
// No escape characters needed inside triple quotes