Some of the main Kotlin language elements include:
Data Types, Variable Declaration, Comments, Functions, Classes, Constructors, Instances, Interfaces, Control Flow, Kotlin Packages and Imports.
Each is summarized below.Data Types
Kotlin provides a rich set of built-in data types, most of which are stored as primitive types at the JVM level (e.g., int, float) for performance, but behave like objects in Kotlin code.
- Numbers: Includes
Byte,Short,Int,Long,Float, andDouble. These are stored as primitives when compiled to JVM bytecode. - Booleans: Represents
trueorfalse. Stored as a primitive boolean type in memory. - Characters: Represented by the
Chartype, holding a single Unicode character. - Strings: Represented by the
Stringtype. Strings are immutable and stored as objects. -
Arrays: Kotlin distinguishes between object arrays (
Array<T>) and primitive arrays (IntArray,DoubleArray, etc.). This distinction impacts memory usage, performance, and behavior, and becomes important when interoperating with Java, converting Java code to Kotlin, or debugging JVM memory and performance issues.
Kotlin also supports nullable versions of all these types using the ? symbol (e.g., Int?, String?) to represent values that may be null.
Like Java and C++, Kotlin is a statically typed language, meaning the type correctness of variables and expressions is determined at compile time. The Kotlin compiler detects and prevents type-related errors early in the development process.
Kotlin also supports type inference, allowing the compiler to determine a variable type based on the assigned value, which eliminates the need for explicit type declarations. This improves readability and reduces boilerplate code. However, explicit type declarations should be used when they improve clarity or prevent ambiguity.
Variable Declaration
Variables are used to store values for a specific data type. For mutable types, key word var is used and for immutable types, either val (compile time values) or const (run type values) is used.
var: Int = 2
or, simply using Kotlin's type inference
var = 2
var can be assigned different value (read-write).
val: String = "This is Kotlin tutorial"
or, using type inference
val = "This is Kotlin tutorial"
val here, is immutable (read-only), equivalent to, as final in Java.
val flag:booleanValue = true
val pi: Double = 3.14
val charValue: Char = 'A'
val intArray: Array = arrayOf(1, 2, 3, 4, 5,6)
val list: List = listOf(1, 2, 3, 4, 5,6)
val set: Set = setOf("apple", "carrot", "orange")
val map: Map = mapOf(1 to "one", 2 to "two", 3 to "three")
val intRange: IntRange = 1..15
val charRange: CharRange = 'A'..'Z'
All above decalred with explicit data type can also be declared by removing it, using type inference, where appropriate.
Note above that Kotlin statements does not require a semicolon (;) to end the statement like many other programming languages, such as Java, C++, etc.
Comments
// This is a single line Kotlin comment
/* This is
* multi-line Kotlin comment
*/
/**
* This is a KDoc comment - used for documentation
* @param name the name to greet
* @return greeting string
*/
//:: This is a special comment often used for IDE directives
// TODO: Mark something that needs to be done later
// FIXME: Highlight problematic code that needs correction
// !! This comment draws attention (use sparingly)
/*
* Multi-line comments can also
* be written without asterisks
*/
// Deprecated: Indicates outdated code
// (Often used with @Deprecated annotation)
Functions
Functions - Functions in Kotlin are declared using the fun keyword and provide reusable blocks of code.
Main Function - The entry point for a Kotlin program.
fun main() {
println("Kotlin Tutorial at www.zyasin.com!")
}
Top-Level Function - Defined directly in files, not tied to any class.
fun greet(name: String): String {
return "Hello, $name!"
}
Function Types:
1. Basic Function - With parameters and return type.
fun add(a: Int, b: Int): Int {
return a + b
}
2. Single-Expression Function - Shorter syntax when function returns a single expression.
fun multiply(a: Int, b: Int) = a * b
3. Default Arguments - Parameters with default values.
fun greet(name: String = "Guest") {
println("Welcome, $name!")
}
4. Named Arguments - Call functions with parameter names.
fun createUser(name: String, age: Int, isAdmin: Boolean = false) { ... }
// Usage:
createUser(age = 25, name = "Alice")
5. Extension Functions - Add functionality to existing classes.
fun String.addExclamation() = "$this!"
// Usage:
"Hello".addExclamation() // "Hello!"
6. Higher-Order Functions - Functions that take other functions as parameters.
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
// Usage:
calculate(5, 3) { x, y -> x + y }
7. Lambda Expressions - Anonymous functions.
val sum = { a: Int, b: Int -> a + b }
val result = sum(2, 3) // 5
// Function type declaration
val greet: () -> Unit = { println("Hello!") }
val add: (Int, Int) -> Int = { a, b -> a + b }
8. Infix Functions - Called without dot and parentheses.
infix fun Int.times(str: String) = str.repeat(this)
// Usage:
3 times "Hi" // "HiHiHi"
9. Tail Recursive Functions - Optimized recursion.
tailrec fun factorial(n: Int, acc: Int = 1): Int {
return if (n == 1) acc else factorial(n - 1, acc * n)
}
10. Operator Overloading - Define behavior for operators.
operator fun Point.plus(other: Point) = Point(x + other.x, y + other.y)
// Usage:
val p1 = Point(1, 2)
val p2 = Point(3, 4)
val p3 = p1 + p2 // Point(4, 6)
Classes
To define a Kotlin class use class keyword, followed by class name.
class ClassName {
// Declare properties (using keywords val or var.)
// Declare functions (using keyword fun.)
}
By default, Kotlin classes are final and cannot be extended unless explicitly marked with the open keyword.
Kotlin provides visibility modifiers like private, protected, internal, and public to control the visibility of class members. By default, class members are public.
Kotlin supports various types of classes, each serving a different purpose:
- Regular classes: Standard classes used to define objects, behavior, and state.
- Data classes: Designed to hold data; automatically provide
equals(),hashCode(),toString(), andcopy()methods. - Sealed classes: Used for restricted class hierarchies; all subclasses must be defined in the same file.
- Enum classes: Represent a fixed set of constants; each constant is an object.
- Object declarations: Define a singleton; useful when only one instance is needed.
- Companion objects: Provide a way to define static members within a class.
- Inner and nested classes: Support structuring classes within classes, with or without access to the outer class.
Abstract Class
For an abstract class in Kotlin, no instance can be created. It is open by default (can't be final!) and can be sub-classed by other non-abstract classes to provide the desired functionality. Abstract methods and fields of abstract class are declared with abstract key word and not final by default, so can be overriden in the implementing class. Any non-abstract members of an abstract class are final by default, which can be only be overriden in child class, once declared as open.
Constructors
For proper object initialization, a Kotlin class can have Primary and Secondary constructors.
Primary Constructor:It is the main way to initialize the properties of a class, defined as part of the class header and responsible for initializing the properties when an object of class is created. To declare a primary constructor keyword constructor can be optionally added just after the class name. The primary constructor defined with the class header do not contain any code. Initialization code is placed within initializer blocks, inside the class body prefixed with the init keyword.
class ClassName(parameters) {
//declare properties (using key words val or var.)
// initializer blocks
}
Secondary Constructor:
A class can have none, one or more secondary constructors. The secondary constructors are created using the constructor keyword. They allow initialization of variables and can provide some logic to the class. One common use of secondary constructor is when extending a class providing multiple cinstructors which each initializing the class in a different way. Compiler decides which constructor to pick based on arguments.
class Student(val studentId: Int, val firstName: String, val lastName: String) {
val fullName: String
init {
fullName = "$firstName $lastName"
}
// Secondary costructor
constructor(firstName: String, lastName: String) : this(0, firstName, lastName)
}
Here the Student class has a secondary constructor that takes only firstName and lastName parameters. The secondary constructor delegates to the primary constructor using the this keyword and provides a default value of 0 for the studentId parameter. This allows to create Student objects without specifying a student ID.
Instances
To define a Kotlin instance or object, call the constructor of class like a regular function i.e. for class Chair, an instance can be declared as var chair = Chair(). Properties and function of a class can be accessed using . notation i.e. name of instance followed by dot and some property or function of class.
Interfaces
In Kotlin, interfaces can contain method implementation as well as abstract methods and properties declaration. An interface needs to be implemented by a class in order for any use. In Kotlin interfaces are not implicitly final. Interfaces can be implemented by any class without any restrictions. However, interface can be forced to be final by using "final" key word before them, which then prevent other classes from implementing it or inheriting from it, however it is extremely rare cases where such need can arise.
interface KotlinInterface {
var someString: String // abstract property
fun someFunction() // abstract method
fun string() = "Some string" // method with default implementation
}
To implement above interface in a class:
class ImplementKotlinInterface : interface KotlinInterface {
override var someString: String = "some string" // property declared in interface implemented
override fun someFunction() = "display string outpt" // function declared in interface implemented
override fun string() = "Some string text overriden" // text in method of interfce overridden
}
Control Flow
val x = 14
if (x > 14) {
println("x is greater than 14")
} else if (x == 14) {
println("x is equal to 14")
} else {
println("x is less than 14")
}
val x = 3
when (x) {
1 -> println("x is 1")
2 -> println("x is 2")
else -> println("x is neither 1 nor 2")
}
for (i in 1..5) {
println(i)
}
fun isPositive(number: Int): Boolean {
if (number > 0) {
return true
} else {
return false
}
}
for (i in 1..10) {
if (i == 5) {
break
}
println(i)
}
for (i in 1..5) {
if (i == 3) {
continue
}
println(i)
}
Kotlin Packages and Imports
In Kotlin, code is organized as packages, which also helps prevent naming conflicts. A package is declared at the top of a Kotlin file using the package keyword. If no package is specified,
the file belongs to the default package.
Kotlin also provides import statements to bring external classes, functions, or objects into the current file. The import keyword allows you to access elements from other packages
without needing to use their fully qualified names.
package com.example.app
import kotlin.math.PI
import kotlin.math.sqrt
fun main() {
println("The square root of 25 is: " + sqrt(25.0))
println("The value of PI is: $PI")
}
Here, the package name is com.example.app and import functions from kotlin.math.
This allows to use PI and sqrt() directly without referring to their full package names.