0
0
Android Kotlinmobile~15 mins

Variables (val, var) and null safety in Android Kotlin - Deep Dive

Choose your learning style9 modes available
Overview - Variables (val, var) and null safety
What is it?
In Kotlin, variables store data that your app uses. You declare variables with val or var. Val means the value cannot change after it is set, like a fixed address. Var means the value can change, like a mailbox where letters come and go. Kotlin also has null safety, which helps prevent errors when a variable might have no value, called null.
Why it matters
Without clear rules for variables and null safety, apps can crash unexpectedly when they try to use missing data. Kotlin’s val, var, and null safety protect your app from these crashes by making you handle data carefully. This leads to more stable apps that users trust and enjoy.
Where it fits
Before learning this, you should understand basic programming concepts like data types and simple variables. After this, you can learn about functions, classes, and how to handle more complex data safely in Kotlin.
Mental Model
Core Idea
Variables in Kotlin are either fixed (val) or changeable (var), and null safety forces you to handle missing data explicitly to avoid crashes.
Think of it like...
Think of val as a locked mailbox that once set, cannot be changed, and var as a regular mailbox where letters can be added or removed. Null safety is like a guard that checks if the mailbox is empty before you open it, preventing surprises.
┌───────────────┐      ┌───────────────┐      ┌───────────────┐
│   val (fixed) │─────▶│  Variable set │      │  Cannot change│
└───────────────┘      └───────────────┘      └───────────────┘

┌───────────────┐      ┌───────────────┐      ┌───────────────┐
│   var (change)│─────▶│  Variable set │─────▶│  Can change   │
└───────────────┘      └───────────────┘      └───────────────┘

┌───────────────┐      ┌───────────────┐      ┌───────────────┐
│ Null Safety   │─────▶│  Nullable?    │─────▶│  Must check   │
│ (safe access) │      │  Yes/No       │      │  before use   │
└───────────────┘      └───────────────┘      └───────────────┘
Build-Up - 6 Steps
1
FoundationUnderstanding val and var basics
🤔
Concept: Learn the difference between val and var for declaring variables.
In Kotlin, use val to declare a variable whose value cannot change. Use var to declare a variable whose value can change. For example: val name = "Alice" // name cannot be changed var age = 25 // age can be changed Try changing name after setting it, and you will get an error. But you can change age anytime.
Result
You can create fixed or changeable variables, and Kotlin enforces these rules at compile time.
Knowing val and var helps you decide which data should stay constant and which can change, making your code safer and clearer.
2
FoundationBasic null safety concept
🤔
Concept: Variables can hold null only if declared nullable, forcing safe handling.
In Kotlin, variables cannot hold null by default. To allow null, add a question mark (?) after the type. For example: var city: String? = null If you try to use a nullable variable without checking, Kotlin will warn you. This prevents crashes from null values.
Result
You learn to declare nullable variables explicitly and Kotlin helps you avoid null errors.
Null safety forces you to think about missing data, reducing app crashes from unexpected nulls.
3
IntermediateSafe calls and the Elvis operator
🤔Before reading on: do you think you can call a method on a nullable variable without checking? Commit to yes or no.
Concept: Use safe calls (?.) and Elvis operator (?:) to handle nullable variables safely.
Safe call operator (?.) lets you call a method or access a property only if the variable is not null. Otherwise, it returns null. Example: val length = city?.length // length is Int? (nullable) Elvis operator (?:) provides a default value if the left side is null: val lengthOrZero = city?.length ?: 0 This means if city is null, lengthOrZero becomes 0 instead of crashing.
Result
You can safely work with nullable variables without risking null pointer errors.
Understanding safe calls and Elvis operator lets you write concise, safe code that handles missing data gracefully.
4
IntermediateNon-null assertions and risks
🤔Before reading on: do you think using !! on a nullable variable is always safe? Commit to yes or no.
Concept: The !! operator forces Kotlin to treat a nullable variable as non-null, risking crashes if null.
Using !! tells Kotlin you are sure the variable is not null. If it is null, your app crashes with a NullPointerException. Example: val length = city!!.length // crashes if city is null Use !! only when you are absolutely sure the variable is not null, otherwise avoid it.
Result
You learn that !! is dangerous and should be used sparingly and carefully.
Knowing the risks of !! helps prevent crashes and encourages safer null handling.
5
AdvancedLateinit and lazy initialization
🤔Before reading on: do you think lateinit variables can hold null? Commit to yes or no.
Concept: lateinit allows var variables to be initialized later without null, lazy initializes on first use.
lateinit var lets you declare a non-null variable without initializing it immediately. You promise to initialize it before use. Example: lateinit var userName: String If you access it before initialization, you get an exception. lazy is for val variables that initialize only when first accessed: val config by lazy { loadConfig() } This delays work until needed.
Result
You can handle variables that need delayed setup safely and efficiently.
Understanding lateinit and lazy helps manage app resources and initialization timing better.
6
ExpertCompiler enforcement and bytecode impact
🤔Before reading on: do you think val and var produce different bytecode or just different compile-time checks? Commit to your answer.
Concept: val and var differ in generated bytecode and runtime behavior; null safety is enforced by compiler and runtime checks.
val generates a final field or property without a setter, making it immutable at runtime. var generates a mutable property with getter and setter. Null safety is mostly a compile-time feature, but some checks (like !!) throw exceptions at runtime. This design balances safety and performance. Understanding this helps optimize code and debug subtle issues.
Result
You grasp how Kotlin’s design enforces safety without heavy runtime cost.
Knowing the compiler and runtime roles clarifies why Kotlin’s null safety is both safe and efficient.
Under the Hood
Kotlin’s compiler treats val as a final variable, generating bytecode without setters, ensuring immutability. Var generates mutable properties with setters. Null safety is enforced by the compiler inserting checks and warnings. Nullable types are represented with wrappers or annotations in bytecode. The !! operator inserts runtime null checks that throw exceptions if violated.
Why designed this way?
Kotlin was designed to improve Java’s null pointer problems by making nullability explicit and enforced at compile time. Val and var provide clear intent for immutability versus mutability, improving code safety and readability. The design balances safety with performance by enforcing most checks at compile time and only adding runtime checks when necessary.
┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│   val (final) │──────▶│  No setter    │──────▶│ Immutable at  │
│               │       │               │       │ runtime       │
└───────────────┘       └───────────────┘       └───────────────┘

┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│   var (mutable)│─────▶│  Getter+Setter│──────▶│ Mutable at    │
│                │      │               │       │ runtime       │
└───────────────┘       └───────────────┘       └───────────────┘

┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│ Nullable type │──────▶│ Compiler check│──────▶│ Safe access   │
│ (String?)    │       │ and warnings  │       │ enforced      │
└───────────────┘       └───────────────┘       └───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Can you safely call a method on a nullable variable without any checks? Commit to yes or no.
Common Belief:You can call methods on nullable variables directly without problems.
Tap to reveal reality
Reality:Calling methods on nullable variables without safe calls or checks causes compile errors or runtime crashes.
Why it matters:Ignoring null safety leads to app crashes that frustrate users and are hard to debug.
Quick: Does val mean the variable’s content can never change, including mutable objects? Commit to yes or no.
Common Belief:Val means the variable and its content are completely unchangeable.
Tap to reveal reality
Reality:Val means the reference cannot change, but the object it points to can be mutable and change internally.
Why it matters:Misunderstanding val can cause bugs when mutable objects are changed unexpectedly despite val declaration.
Quick: Is using !! operator always safe if you think the variable is not null? Commit to yes or no.
Common Belief:Using !! is safe as long as you believe the variable is not null.
Tap to reveal reality
Reality:If the variable is null at runtime, !! causes a crash with NullPointerException.
Why it matters:Overusing !! leads to crashes that null safety aims to prevent.
Quick: Does lateinit allow null values for variables? Commit to yes or no.
Common Belief:lateinit variables can hold null values safely.
Tap to reveal reality
Reality:lateinit variables must be non-null types and cannot hold null; accessing before initialization throws exception.
Why it matters:Misusing lateinit can cause unexpected crashes and confusion about variable state.
Expert Zone
1
Val variables referencing mutable objects can still change internal state, so immutability is about reference, not object content.
2
Null safety annotations and checks integrate with Java interoperability, but some Java code can bypass Kotlin’s null safety, requiring extra care.
3
Lateinit is only allowed for var and non-null types, and misuse can cause runtime exceptions that are hard to trace.
When NOT to use
Avoid lateinit for primitive types or when initialization timing is uncertain; prefer nullable types or lazy initialization. Use !! only when absolutely sure, otherwise prefer safe calls or explicit null checks.
Production Patterns
Use val by default for thread safety and clarity. Use var only when state changes are needed. Use nullable types with safe calls to handle optional data from APIs. Use lazy for expensive initialization and lateinit for dependency injection or Android view binding.
Connections
Immutability in Functional Programming
Builds-on
Understanding val as immutable references connects to functional programming principles where data does not change, improving code predictability.
Optional Types in Swift
Same pattern
Kotlin’s nullable types and Swift’s optionals both enforce explicit handling of missing data, showing a cross-language approach to safer code.
Null Pointer Exceptions in Java
Opposite
Kotlin’s null safety was designed to prevent the common Java problem of null pointer exceptions, highlighting how language design can improve reliability.
Common Pitfalls
#1Trying to change a val variable after initialization.
Wrong approach:val score = 10 score = 15 // Error: Val cannot be reassigned
Correct approach:var score = 10 score = 15 // Correct: Var can be reassigned
Root cause:Confusing val (immutable reference) with var (mutable reference).
#2Accessing a nullable variable without safe calls or checks.
Wrong approach:var name: String? = null println(name.length) // Error: Only safe calls allowed on nullable
Correct approach:var name: String? = null println(name?.length) // Safe call returns null if name is null
Root cause:Ignoring Kotlin’s null safety rules and trying to use nullable variables as non-null.
#3Using !! operator carelessly on nullable variables.
Wrong approach:var city: String? = null println(city!!.length) // Runtime crash if city is null
Correct approach:var city: String? = null println(city?.length ?: 0) // Safe handling with default
Root cause:Overconfidence in variable non-null status leading to runtime exceptions.
Key Takeaways
Kotlin’s val and var keywords clearly distinguish between fixed and changeable variables, improving code safety and clarity.
Null safety in Kotlin forces you to explicitly handle variables that can be null, preventing many common app crashes.
Safe calls (?.) and the Elvis operator (?:) provide concise ways to work safely with nullable variables.
The !! operator should be used sparingly because it can cause runtime crashes if the variable is null.
Understanding how Kotlin enforces these rules at compile time and runtime helps you write robust, maintainable mobile apps.