DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

  1. DZone
  2. Refcards
  3. Getting Started With Kotlin
refcard cover
Refcard #257

Getting Started With Kotlin

Kotlin has become one of the most popular JVM languages in the past few months, partly because it experienced a lot of attention in the Android community after Google made Kotlin an official language for Android development. Download this Refcard to start working with this open-source language, which can be found on GitHub.

Download Refcard
Free PDF for Easy Reference
refcard cover

Written By

author avatar Simon Wirtz
Software Developer, simon-wirtz.de
Table of Contents
► Introduction ► Where to Start Coding ► Basic Syntax ► Top Features ► Idiomatic Kotlin ► Resources
Section 1

Introduction

Kotlin has become one of the most popular JVM languages in the past few months. One special reason is that it experienced a lot of attention in the Android community after Google made Kotlin an official language for Android development. Kotlin is being developed by JetBrains, who are responsible for the most famous IDEs out there, most notably IntelliJ IDEA. Nevertheless, it’s an open source language, which can be found on GitHub.

The language is said to be very concise, safe in terms of error frequency, interoperable with Java and also offers many features that enable functional programming, writing type-safe DSLs and much more. Beside the JVM, Kotlin can compile for most Android versions, down to machine code using LLVM and can also be transpiled to JavaScript. Kotlin has already been adopted in many popular frameworks and tools such as Spring and Gradle. It continues to gain traction in multiple domains, and there has never been a better time to get started with Kotlin.

Section 2

Where to Start Coding

When you want to start writing your first Kotlin code there are quite a few ways to do that. Apparently, the recommended way is to work with IntelliJ IDEA, which offers the best support. As an alternative, one could also start with the command line or use JetBrains’ Kotlin web IDE to do some Kotlin Koans. Whichever way you prefer, corresponding tutorials can be found here: kotlinlang.org/docs/tutorials/.

Section 3

Basic Syntax

Kotlin was inspired by many modern programming languages like C#, Groovy, Scala and also Java. Even more, Kotlin can be seen as an extension to the Java language, making it better by adding functionality to existing standard classes (e.g. String, List) and of course by providing great features, which are in large part enabled by applying compiler-supported techniques. As in Java, Kotlin programs are entered via a main method, such as the following:

​x
1
package de.swirtz.dzone.refcard.examples
2
​
3
fun main(args: Array<String>): Unit {
4
    val inserted = "Kotlin"
5
    println("Let's get started with $inserted")
6
}

What we can see in this snippet is:

  • Functions are initiated by the keyword fun, followed by a name
  • Parameters and also variables in Kotlin are declared by defining a name and a type, both separated by a colon as you can see in args: Array<String>
  • The return type of the main is Unit, also prefaced by a colon. In case of a Unit return, which corresponds to Java’s void, the compiler does not require you to explicitly define the return type, so the part : Unit could be omitted
  • Kotlin does not require you to use semicolons for separating statements (in most cases)
  • Type inference is supported in many situations as shown with val inserted, which also could be declared with an explicit type as val inserted: String
  • String templates can be used, which means that it’s possible to include variables and even expressions in Strings directly using $varname or ${statement} syntax
  • main is declared without a wrapping class around it. Functions and variables in Kotlin may be declared at “top-level”, i.e directly inside a package
  • No visibility modifier is used here. Functions, classes, variables etc. are public by default. When different visibility is needed, choose from:
    Keyword Effect on Top-Level declarations [1] Cl Effect on ass Members
    public visible everywhere visible everywhere if class is accessible
    private visible inside the file only visible inside the class only
    protected - v isible in class and subclasses
    internal visible inside the same module [2] th visible in e same module, if class is accessible
    1: Functions, properties and classes, objects and interfaces can be declared on the “top-level”
    2: A module is a set of Kotlin files compiled together: an IntelliJ IDEA module, a Maven project, a Gradle source set
  • Variables defined as val cannot be re-assigned, i.e. are read-only. Alternatively, if mutability is inevitable, var can be utilized, as shown in the next example:
    2
    1
    var mutableVar = StringBuilder("first")
    2
    mutableVar = StringBuilder("second")
  • Constructor is invoked without the new keyword, which is omitted from kotlin

Control Flow: Conditions

In Kotlin you can make use of if, when, for and while for controlling the behavior of your code. Let’s look at conditions first.

If-Statement

6
1
val min: Int
2
if (x < y) {
3
    min = x
4
} else {
5
    min = y
6
}

It’s important to know, that many statements in Kotlin can also be used as expressions, which for instance makes a ternary operator obsolete and apparently shortens the code in most cases:

1
1
val min = if (x < y) x else y

When-Statement

A when statement is very similar to switch operators and could, in theory, easily replace if-statements as they are much more powerful.

9
1
val y = when (x) {
2
    0 -> "is zero"
3
    1 -> "is one"
4
    2, 3 -> "two or three"
5
    is Int -> "is Int"
6
    is Double -> "is Double"
7
    in 0..100 -> "between 0 and 100"
8
    else -> "else block"
9
}

In a when statement, which can also be used as an expression, all branches are tried to match the input until one condition is satisfied. If no branch matches, the else is executed. As shown in the snippet, when branch conditions can be values, types, ranges and more.

Control Flow: Loops

For-Loop

In Kotlin, there’s no conventional for-loop, as you know it from C or Java. Instead, foreach loops are the default.

3
1
for (c in "charSequence") {
2
    //
3
}

In many cases, looping with an index is necessary, which can easily be achieved with the indices property that is defined for arrays, lists and also CharSequences for example.

3
1
for (i in "charSequence".indices) {
2
   println("charSequence"[i])
3
}

Another way of iterating with indices is possible by using withIndix().

3
1
for ((i,c) in "charSequence".withIndex()) {
2
        println("$i: $c")
3
}

Last but not least, Kotlin has ranges, which can also be utilized for indexed iterations as the following shows:

3
1
(0 .. "charSequence".length-1).forEach {
2
        print("charSequence"[it])
3
}

The range in this example is expressed with the common .. syntax. To create a range which does not include the end element (s.length), the until function is used: (0 until s.length).

While-Loop

Constructs with while or do-while loops are straight-forward, all works as known from other common languages.

Basic Types

In Kotlin everything looks like an object to the user, even primitive types. This means, member functions can be called on every type, although some will be represented as JVM primitives at runtime.

Numbers

The default number types are: Double, Float, Long, Int, Short, Byte * Underscores can be used to make large numbers more readable: val million = 1_000_000 * Number types offer conversion methods like toByte(): Byte, toInt(): Int , toLong(): Long * Characters are no number type in Kotlin

Chars

A Char represents characters and cannot be treated as a number. They are declared within single quotes, e.g. '42' An explicit conversion from a Char to an Int can be accomplished with the toInt() method

Booleans

Booleans can have the two common values true and false * They can be operated on with: ||, && and !

Strings

Strings are immutable sequences of characters. * They offer an index operator [] for accessing characters at specified positions * A string literal in Kotlin looks like "Hello World" or """Hello World with "another String" in it""" * The latter is called raw string that can contain any character without needing to escape special symbols * Strings in Kotlin may contain template expressions

Arrays

An array is represented by the class Array, which offers very useful methods to the client. * Values can be obtained via get(index) or [index] * Values can be set via set(index, value) or [index]=value * Arrays are invariant, i.e. an Array<String> cannot be assigned to a variable of type Array<Any> * Special types for arrays of primitive types exist as IntArray or ShortArray for instance. Using those will reduce the boxing overhead.

Classes

A simple class can be declared like in this snippet:

1
1
class Person constructor(name: String) {}

The primary constructor is part of the class header, secondary constructors can be added in the class body. In the shown case, the constructor keyword could also be omitted, since it’s only mandatory if you want to add annotations or visibility modifiers (default: public). Constructor parameters such as name can be used during the initialization of an object of this class. For this purpose, an init block would be necessary, because primary constructors can’t contain code directly. Constructor arguments can also be used in property initializers that are declared in the class body, as shown here.

6
1
class Person(name: String, age: Int) {
2
    init {
3
        println("new Person $name will be born.")
4
    }
5
    val ageProp = age
6
}

As mentioned, Kotlin classes can contain properties, which are accessed by simply calling obj.propertyName to get a property’s value and obj.propertyName = "newValue" to modify the value of a mutable (var) property. Declaring properties for classes can also be done in the primary constructor directly, which makes the code even more concise. Like in all methods, Kotlin supports default parameters for parameters, set with “=”.

1
1
class Person(val name: String, val age: Int = 50)

Same as with local variables, instead of val, a property can be declared mutable using var instead. Note that you don’t have to write an empty class body if no content is defined.

Special Classes

Besides ordinary classes, Kotlin knows a few special class declarations, which are worth knowing. The following will give a quick overview.

Type Explanation
data class Adds standard functionality for toString, equals, hashCode etc.
sealed class Restricts class hierarchies to a set of subtypes. Useful with when
Nested class Classes can be created in other classes, also known as “inner class”
enum class Collect constants that can contain logic
object declarations Used to create Singletons of a type

Of course, Kotlin also supports inheritance through interfaces and abstract classes.

Function Types and Lambdas

In order to be able to understand idiomatic Kotlin code, it’s essential to recognize how function types and especially lambdas look like. Just as you can declare variables of type Int or String, it’s also possible to declare variables of function types, e.g. (String) -> Boolean.

2
1
    val myFunction: (String) -> Boolean = { s -> s.length > 3 }
2
    myFunction("HelloWorld")

The variable is declared as a function type that takes a String argument and returns a Boolean. The method itself is defined as a lambda enclosed in curly braces. In the shown lambda, the String parameter is declared and named before the -> symbol, whereas the body follows after it.

Lambda Special Syntax

The language designers decided on some special lambda features, which make the usage even more powerful.

  1. it: implicit name of single parametersIn many cases, lambdas are used with single parameters like in the previous example. In such situations, you don’t have to give the parameter an explicit name. Instead, the implicit name it can be used.
2
1
    val myFunction: (String) -> Boolean = { it.length > 3 }
2
    myFunction("HelloWorld")
  1. For unused parameters, use _In some cases, it might be unnecessary to make use of every possible available parameter in a lambda. The compiler warns the developer about such unused variables, which can be avoided by naming it with an underscore.
2
1
    val myFunction: (String, Int) -> Boolean = { s, _ -> s.length > 3 }
2
    myFunction("HelloWorld", 42)

Higher-Order Functions

If a function takes another function as an argument or returns another function as its result, it’s called a higher-order function. Such functions are essential in Kotlin as many library functions rely on this concept. Let’s see an example.

9
1
fun main(args: Array<String>) {
2
    myHigherOrderFun(2, { it.length > 2 })
3
}
4
​
5
fun myHigherOrderFun(iterations: Int, test: (String) -> Boolean){
6
    (0 until iterations).forEach {
7
        println("$it: ${test("myTestString")}")
8
    }
9
}

The function myHigherOrderFun defines two parameters, one of which is another function test. The function takes test and applies a String to it multiple times depending on what the first argument iterations is. By the way, the example uses a range to imitate an indexed for loop here.

The shown main function demonstrates the usage of a higher-order function by calling it with an anonymous function. The syntax looks a bit messy, which is why the language designers decided on a very important convention: If a lambda is the last argument to a function, it can be placed after the closing parentheses or, if it’s the only argument, the parentheses can be omitted completely like shown with forEach above. The following snippet demonstrates this convention applied to an invocation of myHigherOrderFun.

4
1
    //Lambda after closing parentheses
2
    myHigherOrderFun(2) {
3
         it.length>2
4
    }
Section 4

Top Features

There are some features in Kotlin, everybody should be familiar with. These are essential for many libraries, standard functions and also advanced features like Domain Specific Language support.

Null-Safety

The type system differentiates between nullable and non-null types. By default, a class like String cannot reference null, which raises the attention for null-related problems. As opposed to String, the type String? can hold null. This does not make a big difference on its own. Therefore, working with nullable types implies having to handle nullable values in a special way.

13
1
    var b: String? = "couldBeNull"
2
    b = null //okay
3
​
4
    // 1. Access directly: does not compile, could throw NPE
5
    // val len = b.length
6
​
7
    //2. Use safe-operator
8
    val len = b?.length
9
​
10
    //3. Check nullability before accessing
11
    if(b != null){
12
        b.length
13
    }

It’s possible to check whether a variable is not null before accessing it. In such cases, the compiler permits the usage without special safety measures. Alternatively, b?.length expresses: call length on b if it’s not null, otherwise the expression returns null. The return is of type Int? because null may be returned. Chaining such calls is possible, which is very useful. Other operators used with nullable types are shown in the following overview.

Operator Use case Example
!! Ignore warnings of compiler and overcome null checks. Use cautiously only. val x: String? = "nullable"x!!.length
?: The elvis operator is used to give an alternative for null results. val x: String? = "nullable"val len: Int = b?.length ?: 0
as? A safe cast tries to cast a variable in a type and results in null if the cast is not possible. val i: Int? = s as? Int

Extensions

Another essential feature of Kotlin is extensions. An extension is used to extend a class with new functionality without having to inherit from that class. Extensions can have the form of properties and functions. The Kotlin standard library contains a lot of such extensions, like the following defined on String:

4
1
public fun String.substring(range: IntRange): String = substring(range.start, range.endInclusive + 1)
2
​
3
//usage
4
"myString".substring(0..3)

In this example String is the receiver of the defined substring(range: IntRange) function. An extension function can use visible members of its receiver without additional qualifiers since this refers to the receiver. In the snippet, String’s standard method substring(startIndex: Int, endIndex: Int) is called in that way. The extension is called on a String as if it was a regular method.

It’s also possible to extend a class with properties. For example, Int can be extended with a property that represents its version of BigDecimal. This might be useful if otherwise, the constructor of BigDecimal had to be used many times.

4
1
val Int.bd
2
    get() = BigDecimal(this)
3
​
4
val bd: BigDecimal = 5.bd

Extensions are mostly defined on top-level and can be used in other files after they have been imported explicitly.

Lambda with Receiver

Higher-order functions can be even more powerful if used with “lambdas with receiver”. It’s possible to call function literals with a specific receiver object, similar to the extension functions. As a result, members of the receiver can directly be accessed inside the lambda without having to use additional qualifiers. This feature is the foundation for Kotlin’s fantastic support for writing Type-Safe Builders, also known as Domain Specific Languages.

4
1
fun <T> T.apply(block: T.() -> Unit): T {
2
    block()
3
    return this
4
}

This snippet shows a slightly simplified version of the apply function, which is part of Kotlin’s standard library. It’s an extension function on the generic type T, thus can be used with any object. The function takes a function literal with T as its receiver and executes the block before this (the receiver of apply) is being returned.

12
1
data class GuiContainer(var width: Int = 0, var height: Int = 0, var background: String = "red") {
2
    fun printMe() = println(this)
3
}
4
​
5
fun main(args: Array<String>) {
6
    val container = GuiContainer().apply {
7
        width = 10
8
        height = 20
9
        background = "blueish"
10
        printMe()
11
    }
12
}

In this example, the data class GuiContainer is created with default parameters and then the apply method is called on it. It’s possible to set mutable properties and call methods of the receiver GuiContainer like shown with the invocation of printMe() in the end. Since apply returns the receiver after it completes, it can directly be assigned to a variable.

Section 5

Idiomatic Kotlin

Kotlin tries to encourage particular coding idioms to be used. These are partially listed in the documentation and also in some community driven articles. The following will present some of these idioms by example.

  1. Use when as an expression if possible
5
1
fun analyzeType(obj: Any) =
2
    when(obj){
3
        is String -> "is String"
4
        else -> "no String"
5
    }
  1. Use elvis operator with throw and return to handle nullable values
8
1
class Person(val name: String?, val age: Int?)
2
​
3
fun process(person: Person) {
4
    val pName = person.name ?: throw IllegalArgumentException("Name must be provided.")
5
    println("processing $pName")
6
    val pAge = person.age ?: return
7
    println("$pName is $pAge years old")
8
}
  1. Make use of range checks
1
1
fun inLatinAlphabet(char: Char) = char in 'A'..'Z'  
  1. Prefer default parameters to function overloads
5
1
fun greet(person: Person, printAge: Boolean = false) {
2
    println("Hello ${person.name}")
3
    if (printAge)
4
        println("${person.name} is ${person.age} years old")
5
}
  1. Use type aliases for function types
3
1
typealias StringPredicate = (String) -> Boolean
2
​
3
val pred: StringPredicate = {it.length > 3}
  1. Use data classes for multiple return values
7
1
data class Multi(val s: String, val i: Int)
2
​
3
fun foo() = Multi("one", 1)
4
​
5
fun main(args: Array<String>){
6
    val (name, num) = foo()
7
}
  1. Prefer extension functions to utility-style functions
5
1
fun Person.greet(printAge: Boolean = false) {
2
    println("Hello $name")
3
    if (printAge)
4
        println("$name is $age years old")
5
}
  1. Use apply for object initialization
12
1
data class GuiContainer(var width: Int = 0, var height: Int = 0, var background: String = "red") {
2
    fun printMe() = println(this)
3
}
4
​
5
fun main(args: Array<String>) {
6
    val container = GuiContainer().apply {
7
        width = 10
8
        height = 20
9
        background = "blueish"
10
        printMe()
11
    }
12
}
  1. Use compareBy for complex comparisons
2
1
fun sort(persons: List<Person>): List<Person> =
2
        persons.sortedWith(compareBy(Person::name, Person::age))
  1. Use mapNotNull to combine map and filter for non-null values
2
1
fun getPersonNames(persons: List<Person>): List<String> =
2
    persons.mapNotNull { it.name }
  1. Use object to apply Singleton pattern
8
1
object PersonRepository{
2
    fun save(p: Person){}
3
    //...
4
}
5
​
6
//usage
7
val p = Person("Paul", 40)
8
PersonRepository.save(p)
  1. Do not make use of !!
2
1
//Do not use !!, there's always a better solution
2
person!!.address!!.street!!.length
  1. Prefer read-only data structures
7
1
//Whenever possible, do not use mutable Data Structures
2
​
3
val mutableList: MutableList<Int> = mutableListOf(1, 2, 3)
4
mutableList[0] = 0
5
​
6
val readOnly: List<Int> = listOf(1, 2, 3)
7
readOnly[0] = 0 // Does not compile
  1. Use let to execute code if receiver is not null
5
1
fun letPerson(p: Person?) {
2
        p?.let {
3
            println("Person is not null")
4
        }
5
    }
Section 6

Resources

Language References
Official Reference Documentation https://kotlinlang.org/docs/reference/
GitHub repository https://github.com/JetBrains/kotlin
Collection of Tools and Frameworks https://kotlin.link
Operators and Keywords Overview https://kotlinlang.org/docs/reference/keyword-reference.html
Community
Slack https://kotlinlang.slack.com
Twitter https://twitter.com/kotlin
Newsletter http://kotlinweekly.net
Discussion https://discuss.kotlinlang.org
Blogs
JetBrains https://blog.jetbrains.com/kotlin/
Simon Wirtz https://blog.simon-wirtz.de
Misc
Books https://kotlinlang.org/docs/books.html
Online IDE https://try.kotlinlang.org

Like This Refcard? Read More From DZone

related article thumbnail

DZone Article

How to Build Real-Time BI Systems: Architecture, Code, and Best Practices
related article thumbnail

DZone Article

How Kubernetes Cluster Sizing Affects Performance and Cost Efficiency in Cloud Deployments
related article thumbnail

DZone Article

Cloud Security and Privacy: Best Practices to Mitigate the Risks
related article thumbnail

DZone Article

How to Perform Custom Error Handling With ANTLR
related refcard thumbnail

Free DZone Refcard

Java Application Containerization and Deployment
related refcard thumbnail

Free DZone Refcard

Introduction to Cloud-Native Java
related refcard thumbnail

Free DZone Refcard

Java 15
related refcard thumbnail

Free DZone Refcard

Java 14

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: