Kotlin Basic Syntax and Data Types: val vs var, Null Safety, Type Inference & More
1. What is the Basic Structure of a Kotlin Program?
A Kotlin program consists of a package declaration, imports, and a main function as the entry point. It uses .kt files and compiles to JVM bytecode, JavaScript, or native code.
Key Components:
- Package: Optional declaration for namespace (e.g.,
package com.example). - Imports: Import libraries (e.g.,
import kotlin.math.*). - Main Function: Entry point (
fun main() { }). - Top-Level Code: Kotlin allows code outside functions.
Syntax:
package com.example
import kotlin.math.sqrt
fun main() {
println("Hello, Kotlin!")
}
Use Case: Simple console applications or building blocks for Android/iOS apps.
Example: Basic Program Structure
package com.example
import kotlin.math.sqrt
// Top-level function
fun calculateSquare(n: Int): Int = n * n
fun main() {
val message = "Hello, Kotlin!"
println(message)
val number = 5
val square = calculateSquare(number)
println("Square of $number is $square")
}
Note: package defines namespace; import brings in sqrt (unused here for demo). fun defines functions; main is the entry point. Compile and run with kotlinc HelloKotlin.kt -include-runtime -d HelloKotlin.jar and java -jar HelloKotlin.jar.
2. What are val and var in Kotlin?
val: Immutable variable (constant), cannot be reassigned after initialization. Similar to final in Java.
var: Mutable variable, can be reassigned. Similar to regular variables in Java.
Syntax:
val immutable = 10 // Cannot reassign
var mutable = "Hello" // Can reassign
Use Case: val for constants (e.g., PI); var for changing values (e.g., counters).
Example: val and var
fun main() {
val pi = 3.14 // Immutable
println("Pi: $pi")
var counter = 0 // Mutable
counter++
println("Counter: $counter")
// pi = 3.14159 // Error: Val cannot be reassigned
counter = 10
println("Updated counter: $counter")
}
Note: val pi prevents reassignment; var counter allows it. Kotlin's type inference omits types (e.g., Double, Int).
3. What are the Basic Data Types in Kotlin?
Numeric:
Int: 32-bit integer (e.g.,42).Double: 64-bit floating-point (e.g.,3.14).Float: 32-bit floating-point (e.g.,3.14f).
Boolean: True/false (e.g., true, false).
Char: Single character (e.g., 'A').
String: Sequence of characters (e.g., "Hello").
Use Case: Storing numbers, text, or flags for calculations or display.
Example: Basic Data Types
fun main() {
val myInt: Int = 42
val myDouble: Double = 3.14
val myFloat: Float = 3.14f
val myBoolean: Boolean = true
val myChar: Char = 'A'
val myString: String = "Hello, Kotlin!"
println("Int: $myInt")
println("Double: $myDouble")
println("Float: $myFloat")
println("Boolean: $myBoolean")
println("Char: $myChar")
println("String: $myString")
}
Note: Explicit typing (: Type) is optional; Kotlin infers types. Strings use double quotes; chars use single quotes.
4. What is Type Inference and Explicit Typing in Kotlin?
Type Inference: Kotlin automatically deduces variable types from context (e.g., val x = 42 infers Int).
Explicit Typing: Manually specifying types (e.g., val x: Int = 42).
Benefits: Inference reduces boilerplate; explicit typing improves readability for complex types.
Use Case: Inference for simple variables; explicit for function parameters or complex returns.
Example: Type Inference and Explicit Typing
fun main() {
// Type inference
val inferredInt = 42 // Inferred as Int
val inferredString = "Hello" // Inferred as String
// Explicit typing
val explicitInt: Int = 42
val explicitString: String = "Hello"
println("Inferred Int: $inferredInt, Type: ${inferredInt::class.simpleName}")
println("Explicit Int: $explicitInt, Type: ${explicitInt::class.simpleName}")
}
Note: Inference works for primitives; explicit typing is useful for clarity or generics.
5. What are Nullable Types and Null Safety in Kotlin?
Nullable Types: Allow variables to hold null (e.g., String?).
Non-Nullable Types: Cannot hold null (default, e.g., String).
Null Safety: Kotlin's type system prevents null reference exceptions at compile time.
?: Makes a type nullable (e.g.,String?).!!: Force unwraps a nullable type, throwingNullPointerExceptionif null (use cautiously).- Safe Calls:
?.(e.g.,nullable?.method()) returnsnullif the object is null. - Elvis Operator:
?:(e.g.,nullable ?: "default") provides a default if null.
Use Case: Handling optional data safely.
Example: Nullable Types and Null Safety
fun main() {
val nonNullable: String = "Hello"
// nonNullable = null // Error: Type mismatch
var nullable: String? = null
nullable = "World"
// Safe call
val length = nullable?.length ?: 0
println("Length: $length")
// Force unwrap (dangerous)
// val unsafe = nullable!! // Throws NPE if null
// Elvis operator
val message = nullable ?: "Default message"
println("Message: $message")
}
Note: ? allows null; ?. and ?: handle it safely. !! is risky; prefer safe alternatives.
6. Comprehensive Example Combining All Concepts
This example combines program structure, variables, data types, type inference, and null safety in a single Kotlin program.
// Comprehensive Kotlin program
package com.example
// Class with init and variables
class Employee(val name: String, var salary: Double, val deptId: Int) {
// Instance variable
private var bonus: Double = 0.0
// Method
fun calculateBonus(percentage: Double): Double {
bonus = salary * (percentage / 100)
return bonus
}
fun displayInfo(): String {
return "Employee: $name, Salary: $$salary, Bonus: $$bonus, Dept: $deptId"
}
}
fun main() {
// Type inference
val inferredInt = 42 // Inferred as Int
val inferredString = "Hello" // Inferred as String
// Explicit typing
val explicitInt: Int = 42
val explicitDouble: Double = 3.14
val explicitBoolean: Boolean = true
val explicitChar: Char = 'A'
// Nullable types
val nonNullable: String = "Kotlin"
val nullable: String? = null
// Safe call and Elvis
val length = nullable?.length ?: 0
// Variables: val and var
val immutable = "Constant"
var mutable = 10
mutable += 5
// Create object
val emp = Employee("Krishna", 60000.0, 1)
emp.calculateBonus(10.0)
println(emp.displayInfo())
println("Inferred Int: $inferredInt")
println("Length of nullable: $length")
println("Updated mutable: $mutable")
}
Description:
- Structure: Package, class, main function.
- Variables:
val(immutable),var(mutable). - Data Types:
Int,Double,Boolean,Char,String. - Inference/Explicit: Mix of inferred and explicit types.
- Null Safety: Uses
?,?.,?:. - Object:
Employeeclass withval,var, and methods.
7. Common Mistakes and Best Practices
Common Mistakes:
- Program Structure: Omitting
mainfunction, causing no entry point. Incorrect package/import declarations, leading to unresolved references. - Variables: Attempting to reassign
val, causing compilation error. Forgetting to initializevar(if non-nullable). - Data Types: Mixing incompatible types without conversion (e.g.,
Int+Double). ForgettingfforFloatliterals. - Inference/Explicit: Overusing explicit typing when inference suffices, reducing conciseness. Relying on inference for complex types, causing type errors.
- Null Safety: Using
!!excessively, riskingNullPointerException. Forgetting?for nullable types, causing compilation errors. - General: Not handling exceptions in
mainor methods. Ignoring Kotlin idioms (e.g., usingvalovervar).
Best Practices:
- Program Structure: Always define a
mainfunction as the entry point. Use packages for organization; import only needed modules. - Variables: Prefer
valfor immutable data to enforce safety. Usevaronly when reassignment is needed. - Data Types: Leverage type inference for simplicity; use explicit typing for clarity. Use
DoubleoverFloatfor precision unless memory is critical. - Inference/Explicit: Use inference for simple types; explicit for generics or complex expressions.
- Null Safety: Use
?for nullable types; prefer safe calls (?.) and Elvis (?:). Avoid!!unless necessary; handle nulls explicitly. - General: Follow Kotlin coding conventions (e.g., camelCase for variables). Use Kotlin's standard library for common tasks (e.g.,
listOf()). Test with edge cases (e.g., null inputs, type mismatches). Document code with KDoc for classes and functions.