What is Kotlin?

Kotlin is a general-purpose language aimed at making developers happier! Created by JetBrain(the creators of IntelliJ IDEA), Kotlin is concise, safe, interoperable with Java and other languages, and provides many ways to reuse code between multiple platforms for productive programming.

Start your first line of Kotlin with “Hello World”!

				
					fun main() { println("Hello World")}
				
			
OUTPUT: Hello World

Basic Concepts and Syntax

The first step to mastering a new programming language is to know all the basics (variables, control structures, syntax) before moving on to the next level. By following this path you will definitely save yourself a lot of time learning how to code 🙂

You will learn the basic syntax and concepts of Kotlin in this section. You will be able to easily learn the advanced concepts of Kotlin once you have these in mind.

You can read Kotlin doc for a complete introduction to the language.

Print to the standard output

The print function prints whatever you specify to your console window. It is actually a very good debugging tool. If something isn’t acting right, you can use the print function to see what is going on in the program. 

In Kotlin, the print prints its argument to the standard output:

				
					print("Hello ")
print("world!")
				
			
OUTPUT: Hello World!

println prints its arguments and adds a line break, so that the next thing you print appears on the next line:

				
					println("Hello world!")
println(42)
				
			
OUTPUT: Hello World!
42

Comments

Comments are text notes added to the program to provide explanatory information about the source code. A good programmer always writes comments for their codes. In a large project or framework, you will usually find more than half the code is comments.

Just like most modern languages, Kotlin supports single-line (or end-of-line) and multi-line (block) comments:

				
					// This is an end-of-line comment

/* This is a block comment
   on multiple lines. */

				
			

Variables

Variables serve as a way to store and retrieve information. They also label data with descriptive names.

In Kotlin, read-only local variables are defined using the keyword val. It can only be assigned a value once:

				
					val a: Int = 1  // immediate assignment
val b = 2   // `Int` type is inferred
val c: Int  // Type required when no initializer is provided
c = 3       // deferred assignment
				
			

Variables that can be reassigned use the var keyword:

				
					var x = 5 // `Int` type is inferred
x += 1
				
			

Data Types

Data types are a very simple yet extremely important concept found in almost all programming languages. Essentially, data types represent the various types of data your program can handle. As a result, the computer may store and process data of different types in different ways. In this section, we describe the basic types used in Kotlin: numbers, booleans, characters, strings, and arrays.

Numbers

Kotlin provides a set of built-in types that represent numbers.

Type
Size(bits)
Byte
8
Short
16
Int
32
Long
64
Float
32
Double
64

All variables initialized with integer values not exceeding the maximum value of Int have the inferred type Int:

				
					val one = 1 // Int
val threeBillion = 3000000000 // Long
val oneLong = 1L // Long
val oneByte: Byte = 1
				
			

For variables initialized with fractional numbers, the compiler infers the Double type:

				
					val pi = 3.14 // Double
// val one: Double = 1 // Error: type mismatch
val oneDouble = 1.0 // Double
				
			

Kotlin supports the standard set of arithmetical operations over numbers: +-*/:

				
					println(1 + 2)
println(2_500_000_000L - 1L)
println(3.14 * 2.71)
println(10.0 / 3)
				
			
OUTPUT: 3
2499999999
8.5094
3.3333333333333335

Boolean

The type Boolean represents boolean objects that can have two values: true and false

				
					val myTrue: Boolean = true
val myFalse: Boolean = false
				
			

Built-in operations on booleans include:

				
					println(myTrue || myFalse) \\ disjunction (logical OR)
println(myTrue && myFalse) \\ conjunction (logical AND)
println(!myTrue) \\ negation (logical NOT)
				
			
OUTPUT: true
false
false

Characters and String

Characters are represented by the type Char. Character literals go in single quotes: ‘1’.

				
					val aChar: Char = 'a'
println(aChar)
println('\n') //prints an extra newline character
				
			
OUTPUT: a 


Strings in Kotlin are represented by the type String. Generally, a string value is a sequence of characters in double quotes (“”).

				
					val s = "Hello, world!\n"
				
			

String literals may contain template expressions – pieces of code that are evaluated and whose results are concatenated into the string. A template expression starts with a dollar sign ($) and consists of either a name or an expression in curly braces:

				
					val s = "abc"
println("$s.length is ${s.length}") // prints "abc.length is 3"
				
			
OUTPUT: abc.length is 3

Array

Arrays in Kotlin are represented by the Array class. To create an array, use the function arrayOf() and pass the item values to it, so that arrayOf(1, 2, 3) creates an array [1, 2, 3]. Another option is to use the Array constructor that takes the array size and the function that returns values of array elements given its index:

				
					// Creates an Array String with values ["0", "1", "4", "9", "16"]
val asc = Array(5) { i -> (i * i).toString() }
asc.forEach { println(it) }
				
			

Kotlin also has classes that represent arrays of primitive types without boxing overhead: ByteArrayShortArrayIntArray, and so on.

				
					val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2]
				
			

For more information, please refer to Types.

Nullable Reference

Null is a placeholder that means that is not an integer, not a string, not a boolean – not anything really, except something to hold and be a “not there” value. Kotlin aims at eliminating the danger of null references, also known as The Billion Dollar Mistake.

In Kotlin, the type system distinguishes between references that can hold null (nullable references) and those that cannot (non-null references). For example, a regular variable of type String cannot hold null:

				
					var a: String = "abc" // Regular initialization means non-null by default
a = null // compilation error
				
			

To allow nulls, you can declare a variable as a nullable string by writing String?:

				
					var b: String? = "abc" // can be set to null
b = null // ok
print(b)
				
			
OUTPUT: null

For more information, please refer to Null-Safety.

Control Flow

The control flow is the order in which the computer executes statements in a script. The figure below shows four examples of control flow and the corresponding flow chart.

Example codes for four different control flow and corresponding flow charts.

Conditional expressions

In Kotlin, if is an expression: it returns a value. If you’re using if as an expression, for example, for returning its value or assigning it to a variable, the else the branch is mandatory:

				
					val max = if (a > b) {
    print("Choose a")
    a
} else {
    print("Choose b")
    b
}
				
			

when defines a conditional expression with multiple branches. It matches its argument against all branches sequentially until some branch condition is satisfied.

				
					when (x) {
    1 -> print("x == 1")
    2 ->  print("x == 2")
    else ->  { // Note the block
        print("x is neither 1 nor 2")
    }
}
				
			

Loop

The for loop iterates through anything that provides an iterator. For example, if you want to iterate through an array or a list with an index, you can do it this way:

				
					fun main() {
val array = arrayOf("a", "b", "c")
    for (i in array.indices) {
        println(array[i])
    }
}
				
			
OUTPUT: a 
b
c

while loop executes its body continuously while the condition is satisfied:

				
					while (x ->  0) {
    x--
}
				
			

For more information, please refer to Conditions and Loops.

Exceptions

An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program’s instructions.

In Kotlin, to throw an exception object, use the throw expression:

				
					fun main() {
    throw Exception("Hi There!")
}
				
			
OUTPUT: Exception in thread "main" java.lang.Exception: Hi There!

To catch an exception, use the try… catch expression. There may be zero or more catch blocks, and the finally block may be omitted. However, at least one catch or finally block is required:

				
					try {
    // Block 1: some code
} catch (e: SomeException) {
    // Block 2: handler
} finally {
    // Block 3: optional finally block
}
				
			

For more information, please refer to Exceptions.

Functions

Functions are a set of instructions bundled together to achieve a specific outcome. Functions increase the reusability of code. The values can be sent to a function using variables – these are called parameters or arguments. Functions may also return values.

Two ways implementing repeated greetings: with and without function.

Kotlin functions are declared using the fun keyword. Function parameters can have default values, which are used when you skip the corresponding argument:

				
					fun double(x: Int = 0): Int {
    return 2 * x
}
				
			

If a function does not return a useful value, its return type is Unit. Unit is a type with only one value – Unit. This value does not have to be returned explicitly. The Unit return type declaration is also optional:

				
					fun printHello(name: String?): Unit {
    if (name != null)
        println("Hello $name")
    else
        println("Hi there!")
    // `return Unit` or `return` is optional
}

printHello("Kotlin")
				
			
OUTPUT: Hello Kotlin

Functions with block bodies must always specify return types explicitly unless it’s intended for them to return Unit, in which case specifying the return type is optional.

For more information, please refer to Functions.

Creating classes and instances

Class is a very important concept in Object-oriented programming languages like Kotlin. In code, we combine a group of related variables and functions into a unit, we called that unit an object. Classes are the blueprints that define the behavior and information our objects will contain. An instance method is the behavior of Objects.

The bear doodles below reveal the relationship between class and instance. The class ‘Bear’ is a bear doodle template with ‘color’ and ’emotion’ attributes. These three instances of bear have different values of the attributes when they are created from the ‘Bear’ Class.

The relationship between 'Class' and 'Instance'.

Classes in Kotlin are declared using the keyword class:

				
					class InitOrderDemo(name: String) {
    val firstProperty = "First property: $name".also(::println)

    init {
        println("First initializer block that prints ${name}")
    }

    val secondProperty = "Second property: ${name.length}".also(::println)

    init {
        println("Second initializer block that prints ${name.length}")
    }
}

fun main() {
    InitOrderDemo("hello")
}

				
			
First property: hello 
First initializer block that prints hello
Second property: 5
Second initializer block that prints 5

The class declaration consists of the class name, the class header (specifying its type parameters, the primary constructor, and some other things), and the class body surrounded by curly braces. Initialization code can be placed in initializer blocks prefixed with the init keyword. During the initialization of an instance, the initializer blocks are executed in the same order as they appear in the class body, interleaved with the property initializers.

To create an instance of a class, call the class constructor as if it were a regular function:

				
					val invoice = Invoice()
val customer = Customer("Joe Smith")
				
			

Classes can contain:

  • Constructors and initializer blocks
  • FunctionsProperties
  • Nested and inner classes
  • Object declarations

For more information, please refer to Class.

Package definition and imports

A package is a namespace that organizes a set of related classes and interfaces. Conceptually you can think of packages as being similar to different folders on your computer. A source file may start with a package declaration:

				
					//This is file A
package org.example
fun printMessage() { /*...*/ }
class Message { /*...*/ }
				
			

Apart from the default imports, each file may contain its own import directives.

				
					// This is file B
import org.example.Message // Message is now accessible without qualification
import org.test.* // everything in 'org.test' becomes accessible
				
			

For more information, please refer to Packages.