Kotlin Basic Syntax Explained
Kotlin's syntax philosophy: use expressions instead of statements wherever possible, and never write a line you don't need. This lets Alice write code that's 40% shorter than Java while expressing more.
1. What You'll Learn
valvsvar: the immutability-first mindset- String templates and raw strings
- The
whenexpression in all its forms - Ranges and iteration:
../until/step/downTo - Expression-body functions and idiom conventions
2. A Developer's Real Story
(1) Pain Point: Mutable State Causes Concurrency Bugs
Alice used var to define a shared order counter in OrderProcessor. Under high concurrency, data races caused a 2% counting deviation — that's 20,000 miscounted orders at scale.
(2) Immutability-First Solution
KOTLIN
// BAD: mutable shared state
var orderCount = 0 // Race condition!
// GOOD: immutable + functional pipeline
val processedOrders = orders
.filter { it.status == "CONFIRMED" }
.also { println("Processed ${it.size} orders") }
Immutable data is naturally thread-safe.
valis every Kotlin developer's first choice;varis a last resort.
3. val vs var: Immutability First
(1) Basic Syntax
KOTLIN
// val: read-only (immutable reference) - PREFERRED
val orderId = "ORD-001" // Type inferred as String
val total: Double = 299.99 // Explicit type
// var: mutable (reassignable) - USE SPARINGLY
var status = "PENDING" // Can be reassigned
status = "CONFIRMED" // OK
// val does NOT mean the object is immutable
val items = mutableListOf<Order>() // Reference is val, list is mutable
items.add(Order("ORD-002", 150.0, "NEW")) // OK - modifying the list
// items = mutableListOf() // ERROR - cannot reassign val
(2) val vs var Comparison
| Dimension | val |
var |
|---|---|---|
| Reassignable | No | Yes |
| Thread safety | Reference immutable, naturally safe | Needs synchronization |
| Recommendation | Preferred | Last resort |
| Java analog | final |
Regular variable |
| Under the hood | Read-only reference (object may be mutable) | Mutable reference |
4. String Templates
(1) Basic Templates
KOTLIN
val orderId = "ORD-001"
val total = 299.99
// Simple variable reference
println("Order: $orderId")
// Expression in template
println("Total: \$$total USD")
println("Tax: \$${total * 0.08} USD")
// Arbitrary expression with ${}
val items = listOf("Widget", "Gadget")
println("Item count: ${items.size}, First: ${items[0]}")
(2) Raw Strings (Multiline)
KOTLIN
val receipt = """
|Order ID: ORD-001
|Total: $299.99 USD
|Status: CONFIRMED
""".trimMargin()
// Alternative: trimIndent
val json = """
{
"order_id": "ORD-001",
"total": 299.99
}
""".trimIndent()
(3) String Template Comparison
| Feature | Java | Kotlin |
|---|---|---|
| Variable reference | "Order " + id |
"Order $id" |
| Expression | "Tax: " + (t * 0.08) |
"Tax: ${t * 0.08}" |
| Multiline | No native support | """ ... """ |
| Indent handling | Manual | trimMargin() / trimIndent() |
5. when Expression
when is switch's comprehensive upgrade — it's an expression with a return value that can match types, ranges, and arbitrary conditions.
(1) Basic Usage
KOTLIN
// when as expression (must be exhaustive)
val status = "CONFIRMED"
val label = when (status) {
"PENDING" -> "Waiting for payment"
"CONFIRMED" -> "Payment received"
"SHIPPED" -> "In transit"
"CANCELLED" -> "Order cancelled"
else -> "Unknown status"
}
(2) Advanced Matching
KOTLIN
// Multiple values
when (status) {
"PENDING", "NEW" -> processNewOrder()
in listOf("CONFIRMED", "PAID") -> shipOrder()
else -> handleOther()
}
// Range matching
val quantity = 150
when (quantity) {
in 1..10 -> println("Small order")
in 11..100 -> println("Medium order")
in 101..1_000 -> println("Large order")
else -> println("Bulk order")
}
// Type matching
fun describe(obj: Any): String = when (obj) {
is String -> "String of length ${obj.length}"
is Int -> "Integer: $obj"
is List<*> -> "List with ${obj.size} elements"
else -> "Unknown type"
}
(3) when Decision Tree
flowchart LR
A[when status] --> B["PENDING, NEW"]
A --> C["CONFIRMED, PAID"]
A --> D["SHIPPED"]
A --> E["CANCELLED"]
A --> F[else]
B --> B1[processNewOrder]
C --> C1[shipOrder]
D --> D1[trackShipment]
E --> E1[refundOrder]
F --> F1[handleOther]
(4) when vs switch
| Dimension | Java switch | Kotlin when |
|---|---|---|
| Return value | Statement, no return | Expression, returns value |
| Multi-value match | Requires fall-through | "A", "B" comma-separated |
| Range match | Not available | in 1..100 |
| Type match | Not available | is String |
| Guard condition | Not available | x > 0 arbitrary |
| Exhaustiveness check | None | Compiler-enforced (expression mode) |
6. Ranges and Iteration
(1) Range Operators
KOTLIN
// Closed range: includes both ends
for (i in 1..5) print("$i ") // 1 2 3 4 5
// Half-open range: excludes end
for (i in 1 until 5) print("$i ") // 1 2 3 4
// Step
for (i in 1..10 step 2) print("$i ") // 1 3 5 7 9
// DownTo
for (i in 5 downTo 1) print("$i ") // 5 4 3 2 1
// Char range
for (c in 'A'..'E') print("$c ") // A B C D E
(2) Collection Iteration
KOTLIN
val orders = listOf(
Order("ORD-001", 299.99),
Order("ORD-002", 1_500.00),
Order("ORD-003", 45.50)
)
// Iterate with index
for ((index, order) in orders.withIndex()) {
println("[$index] ${order.id}: \$${order.total} USD")
}
// Iterate map
val statusMap = mapOf("ORD-001" to "SHIPPED", "ORD-002" to "PENDING")
for ((id, status) in statusMap) {
println("$id -> $status")
}
(3) Range Operator Quick Reference
| Operator | Meaning | Example | Result |
|---|---|---|---|
.. |
Closed range | 1..5 |
1,2,3,4,5 |
until |
Half-open range | 1 until 5 |
1,2,3,4 |
step |
Step size | 1..10 step 3 |
1,4,7,10 |
downTo |
Decreasing | 5 downTo 1 |
5,4,3,2,1 |
in |
Membership check | 3 in 1..5 |
true |
7. Expression-Body Functions and Idioms
(1) Expression-Body Functions
KOTLIN
// Block body
fun calculateTax(total: Double): Double {
return total * 0.08
}
// Expression body (more concise)
fun calculateTax(total: Double): Double = total * 0.08
// Type inference with expression body
fun calculateTax(total: Double) = total * 0.08
(2) Kotlin Idioms
KOTLIN
// 1. Semicolons are optional
val x = 1 // No semicolon needed
// 2. Trailing lambda convention
orders.filter { it.total > 1_000 } // lambda outside parens
// 3. It keyword for single-parameter lambda
orders.map { it.id } // 'it' = implicit parameter
// 4. String template over concatenation
val msg = "Order $orderId confirmed" // Not "Order " + orderId + " confirmed"
// 5. Expression body for simple functions
fun isHighValue(order: Order) = order.total > 10_000
(3) Java vs Kotlin Idiom Comparison
| Idiom | Java | Kotlin |
|---|---|---|
| Semicolons | Required | Optional |
| String concat | + operator |
$ template |
| Simple functions | Block body | Expression body |
| Lambda placement | Inside parens | Trailing outside parens |
| Single-parameter lambda | Named parameter | it keyword |
8. Complete Example: OrderProcessor Order Routing
KOTLIN
// ============================================
// OrderProcessor - Order Routing Engine
// Feature: Route orders based on status and value
// ============================================
data class Order(val id: String, val total: Double, val status: String)
fun routeOrder(order: Order): String = when {
order.status == "CANCELLED" -> "REFUND_QUEUE"
order.total > 10_000 -> "VIP_PIPELINE"
order.total > 1_000 -> "PRIORITY_PIPELINE"
order.status == "CONFIRMED" -> "STANDARD_PIPELINE"
order.status in listOf("PENDING", "NEW") -> "WAITING_QUEUE"
else -> "MANUAL_REVIEW"
}
fun processBatch(orders: List<Order>) {
for ((index, order) in orders.withIndex()) {
val pipeline = routeOrder(order)
val priority = when (pipeline) {
"VIP_PIPELINE" -> "CRITICAL"
"PRIORITY_PIPELINE" -> "HIGH"
"STANDARD_PIPELINE" -> "NORMAL"
else -> "LOW"
}
println("[${index + 1}] ${order.id} -> $pipeline (Priority: $priority)")
}
}
fun main() {
val orders = listOf(
Order("ORD-001", 299.99, "CONFIRMED"),
Order("ORD-002", 15_000.00, "CONFIRMED"),
Order("ORD-003", 2_500.00, "PENDING"),
Order("ORD-004", 45.50, "CANCELLED"),
Order("ORD-005", 750.00, "NEW")
)
println("=== Order Routing Report ===")
processBatch(orders)
// Summary with functional pipeline
val pipelineCounts = orders
.map { routeOrder(it) }
.groupingBy { it }
.eachCount()
println("\n=== Pipeline Distribution ===")
for ((pipeline, count) in pipelineCounts) {
println(" $pipeline: $count orders")
}
}
Output:
TEXT
=== Order Routing Report ===
[1] ORD-001 -> STANDARD_PIPELINE (Priority: NORMAL)
[2] ORD-002 -> VIP_PIPELINE (Priority: CRITICAL)
[3] ORD-003 -> PRIORITY_PIPELINE (Priority: HIGH)
[4] ORD-004 -> REFUND_QUEUE (Priority: LOW)
[5] ORD-005 -> WAITING_QUEUE (Priority: LOW)
=== Pipeline Distribution ===
STANDARD_PIPELINE: 1 orders
VIP_PIPELINE: 1 orders
PRIORITY_PIPELINE: 1 orders
REFUND_QUEUE: 1 orders
WAITING_QUEUE: 1 orders
❓ FAQ
Q Can I modify the contents of a val collection?
A Yes. val only guarantees the reference is immutable — the collection contents can still change. For truly immutable collections, use
listOf() instead of mutableListOf().Q Does when always require else?
A When
when is used as an expression, the compiler requires exhaustiveness — you must cover all branches or add else. When used as a statement, else is optional.Q Are
1..5 and 1 until 6 the same?A Same result, different semantics.
1..5 means "from 1 to 5 inclusive", 1 until 6 means "from 1 up to (but not including) 6". When iterating list indices, until is more common.Q When should I use expression-body functions?
A Use expression bodies when the function is a single expression. Use block bodies for anything with 2+ lines of logic. Readability is the top priority.
Q What's the difference between
$var and ${expr} in string templates?A
$var can only reference simple variable names; ${expr} can contain any expression, like ${items.size} or ${total * 0.08}.Q Can when match floating-point ranges?
A Technically yes, but floating-point precision issues can cause unexpected results. Prefer integer ranges or explicit comparisons.
▶ Example: val vs var
KOTLIN
val name = "Alice" // immutable
var age = 30 // mutable
age = 31 // OK
// name = "Bob" // compile error
Output:
TEXT
Compiles; reassigning name fails
▶ Example: when Expression
KOTLIN
val score = 85
val grade = when {
score >= 90 -> "A"
score >= 80 -> "B"
else -> "C"
}
println(grade)
Output:
TEXT
B
▶ Example: for Loop
KOTLIN
for (i in 1..3) println(i)
for (s in listOf("a", "b")) println(s)
Output:
TEXT
1
2
3
a
b
📖 Summary
valfirst,varlast — immutable references are naturally thread-safe- String templates with
$/${}replace string concatenation;"""for multiline whenisswitch's expressive upgrade: multi-value, range, type, and guard matching- Range operators:
..(closed),until(half-open),step,downTo - Expression-body functions make simple functions concise; readability decides the trade-off
- Kotlin idioms: no semicolons, trailing lambdas,
itkeyword, string templates
📝 Exercises
- Beginner (⭐) : Write a function using
valand string templates that outputs an order summary"ORD-001: $299.99 USD (CONFIRMED)". Hint:val id = "ORD-001",val total = 299.99 - Intermediate (⭐⭐) : Implement a discount calculator with
when: > 10,000 → 20% off, > 5,000 → 10% off, otherwise full price. Hint:when {}guard conditions - Challenge (⭐⭐⭐) : Implement a progressive tax calculator using ranges and
when. Different income brackets apply different tax rates. Hint:when { income in range -> ... }



