Kotlin is quickly joining the ranks of the most popular programming languages. Now that Google supports Kotlin for Android app development as the primary choice over Java, we’ll only see more developers making the switch. The job market for Kotlin developers has skyrocketed across the board. In addition to mobile development, it can be used for virtually anything, including web applications and embedded devices.
In this post, we'll take a look at the following:
- What is Kotlin?
- How is Kotlin used?
- Why you should learn Kotlin
- Why developers prefer Kotlin for Android development
- Java vs. Kotlin
- Introduction to Kotlin language and syntax
- What to learn next?
By the end of this post, you'll have an understanding of the benefits of Kotlin, and you'll be ready to write your own simple scripts and applications.
What is Kotlin?
Kotlin is an open-source, statically typed programming language. It can transpile to Java bytecode to run on the Java Virtual Machine (JVM) or Android. Interestingly, it can also transpile to JavaScript code or native bytecode, allowing you to use it for many different use cases.
Kotlin is developed by JetBrains, the company behind the IntelliJ IDEA and other development tools. They designed Kotlin to be 100% interoperable with Java, meaning that you can use any Java libraries and frameworks in Kotlin, and vice versa.
How is Kotlin used?
Currently, it’s most prominent for Android application development. However, its usage for developing server-side applications for the JVM is increasing.
Additionally, it can be used to write web applications by transpiling to JavaScript. Kotlin then lets you use popular libraries and frameworks such as React and VueJS.
It’s useful to know about the corresponding sub-projects in case you encounter them:
- Kotlin/JVM: lets you write JVM applications by transpiling to Java bytecode (e.g., Android development, Spring services, desktop applications)
- Kotlin/JS: lets you write web applications by transpiling to JavaScript (e.g., React apps, and Vanilla JS apps)
- Kotlin/Native: lets you write applications for any target platform such as embedded devices or iOS (e.g., iOS apps, microcontroller programming)
As a side note, Kotlin supports multi-platform application development, which enables you to share code between apps for different platforms. The most obvious use case is to share core functionality between your Kotlin Android app and your Kotlin iOS app.
Why should you learn Kotlin?
Learning Kotlin can teach you a lot about language design and some of the shortcomings of Java that you may not have been aware of previously. Therefore, it can be a great way to learn about modern programming language features that you will encounter in other languages as well, such as TypeScript, Scala, Go or Rust.
Apart from this, there are many companies actively looking for Kotlin developers, especially in the Android development space. So having experience in Kotlin can give you an edge in the interview process.
But even without the goal of landing a Kotlin developer job, learning the language and its concepts will allow you to quickly master other modern languages such as TypeScript, Scala, and Swift because they share many language concepts.
Why developers prefer Kotlin for Android development
In 2019, Google announced that the Kotlin programming language is now its preferred language for Android app development, as opposed to Java. For a lot of developers, this is a breath of fresh air. Java, for all its strengths, has its share of detractors as well. So, here are a few reasons why developers are making the switch to Kotlin.
100% interoperability with Java
Kotlin and Java are 100% interoperable, meaning you can have any percentage of code written in Kotlin, and the rest in Java, and it will all work together. So you don't have to worry about how it will affect your legacy code.
Additionally, there is a tool in Android Studio that allows you to instantly “translate” Java into Kotlin.
Boilerplate code
In Kotlin, you can accomplish the same task with fewer lines of code. Just take a look at this click listener example:
Java:
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Do whatever you want to
}});
Kotlin:
view.setOnClickListener { // Do whatever you want to }
There is no NullPointerException
With Kotlin, you needn't worry about NPEs because null safety is built into Kotlin's type system. This way you can catch NPEs at compile time instead of at runtime.
Great IDE and Tooling support
Kotlin has great support because it's backed by JetBrains, a company that specializes in creating some of the most used IDEs in the world. With a strong community behind the language and tools, you'll always have support when you need it.
All of Android Studio's IDE features work perfectly in Kotlin. You can mix and match Kotlin and Java code in the same project, and everything still works.
Java vs. Kotlin
Size, complexity, and quality of code
While using Java, developers typically have to write more lines of code, while Kotlin enables developers to accomplish the same tasks without writing so much code, making it more expressive.
Further, it helps developers to make code more organized, readable and reusable. So, some developers opt for Kotlin to develop a concise, readable and maintainable code base.
To help manage the quality of your code, Kotlin makes use of type inferencing, eliminating much of the frustrating and overly tedious syntax that Java developers face. Often, code written in Kotlin is more concise, but it also happens to be a little more complex for those used to programming in Java.
Null Safe
In Java, NullPointerException causes a lot of frustration for developers, they can even be the main reason why you would experience crashes in your app.
However, in Kotlin, all types of variables are non-nullable by default. So if you try to assign or return null values, Kotlin will catch NPEs at compile time.
Coroutines support
In Java, whenever you start a long running process with CPU intensive operations, the corresponding thread will be blocked. You can create multiple threads in the background, but managing them is a complex task.
In Kotlin you can create multiple threads to run long processes, and with coroutine support, it will suspend execution at a certain point without blocking threads.
Type inference
In Java you need to specify a type of each variable when you declare it. In Kotlin, you don't need to specify the type of each variable.
Functional programming
Java has support for functional programming but it’s only available in Java 8, whereas most Android development is done with Java 6 and 7.
Kotlin is a mix of functional and procedural programming which consists of many useful methods such as lambdas, higher-order functions, lazy evaluation, etc. Most of these methods are not offered for Android developers in Java 8.
Introduction to Kotlin language and syntax
Kotlin aims to be a readable, pragmatic, safe, and interoperable programming language:
Readability is supported by language features such as type inference, data classes, and infix functions. Such features allow writing concise code without losing readability.
Pragmatism is crucial because Kotlin is for large-scale enterprise software development. JetBrains use it themselves to develop their IDEs. Thus, Kotlin incorporates industry feedback and addresses issues of large-scale software development.
Safety aims to prevent common software bugs by design. This is aided by several language features such as nullable types (to prevent null pointer exceptions) and by nudging you towards best practices such as designing for inheritance.
-
Interoperability with Java is a major selling point of Kotlin and a necessary base for its widespread adoption in the JVM world. Interoperability allows Kotlin and Java to be used side by side, including the use of Java libraries or frameworks from Kotlin.
- For instance, the Kotlin standard library interoperates with Java by reusing the Java Collections API. Similarly, it interoperates with JavaScript in the context of Kotlin/JS.
Now that you have a basic understanding of the philosophy of the language, let's dive in and understand how to use this language.
Read-only vs Mutable variables
Let’s start with the Kotlin basics: declaring variables. Kotlin fundamentally differentiates between read-only and mutable data.
Mutable variables
To declare a mutable variable, you use the var
keyword:
var number = 17
println("number = $number")
number = 42 // var can be reassigned
println("number = $number")
Mutable means that the variable can be reassigned to a different value after initial assignment.
Read-only variables
In contrast, a read-only variable can be declared using val
(instead of var
):
val number = 17
println("number = $number")
number = 42 // Not allowed, throws an exception
Read-only means that the variable cannot be reassigned once initialized.
You should prefer read-only variables to mutable ones whenever possible, i.e., whenever you don’t have to change the value after initialization.
Tip: Prefer
val
tovar
to simplify data flow and facilitate reasoning about your code.
Summary
Kotlin differentiates between read-only and mutable variables at declaration time, forcing you to think about the mutability of state from the start.
-
val
lets you declare read-only variables. -
var
lets you declare mutable variables. - Good practice is to prefer
val
overvar
whenever possible to reduce mutability and therefore facilitate understanding of the program’s state and data flow.
Basic data types
Here, we'll take a look at integers, floating point numbers, text, and booleans.
Integers
There are four basic data types to store integer numbers of different sizes in Kotlin:
val byte: Byte = 127
val short: Short = 32767
val int: Int = 2147483647
val long: Long = 9223372036854775807
Floating Point Numbers
Additionally, Kotlin has Float
and Double
to store floating point numbers up to different precision and sizes:
val float: Float = 3.4028235e38f
val double: Double = 1.7976931348623157e308
Two things to note:
- The
e
in both values denotes exponentiation, for instance10e3 == 1000
. - In order to denote a
Float
value, you have to add thef
suffix. Otherwise, Kotlin infersDouble
as the type of the number.
Text
Kotlin uses the Char
type for single characters and String
for arbitrary sequences of characters:
val character: Char = '#'
val text: String = "Learning about Kotlin's data types"
Single characters are denoted using single quotes ''
, whereas basic strings use double quotes ""
.
However, you can also use multiline strings by wrapping your string into three double quotes: """<multiline string here>"""
.
Booleans
Finally, Kotlin uses Boolean
to store either true
or false
:
val yes: Boolean = true
val no: Boolean = false
Summary
Here’s what you should take away from this section:
- Kotlin has
Byte
,Short
,Int
, andLong
as basic types for integer numbers. - Kotlin uses
Float
andDouble
for floating point numbers. AFloat
is denoted with a trailingf
, as in17f
. - Kotlin has
Char
to store single characters andString
to store strings of text. - Kotlin’s basic types map to Java’s primitive types when targeting the JVM (and
String
maps toString
).
Kotlin's type inference
Type inference is a compiler feature that allows you to omit types in your code when the compiler can infer it for you.
Type Inference in Kotlin
Kotlin’s compiler can infer the types of most variables, so adding the type is optional:
// Run the code to see the variable's types
val string = "Educative"
val int = 27
val long = 42L
val double = 2.71828
val float = 1.23f
val bool = true
Type Inference for Literals
The compiler automatically infers that the string variable must have type String
because it’s assigned to the value "Educative"
.
For integer values, the compiler infers Int
by default. You can use the L
suffix as in 42L
to transform the value into a Long
. Similarly, the compiler infers Double
for floating point numbers unless you add an f
as suffix as in 1.23f
, in which case it is considered a Float
. There’s no such shortcut suffix for Byte
or Short
because these aren’t used as often.
Type Inference for Objects
Naturally, type inference doesn’t only work with literal values on the right-hand side. The compiler can infer types of object just as easily:
import java.util.*
import java.time.*
import java.io.*
val stringBuffer = StringBuffer("PREFIX")
val localDate = LocalDate.now()
val file = File("foo.txt")
Summary
Here are the key takeaways:
- The Kotlin compiler can infer most types.
- Writing down the type explicitly is optional in these cases.
- You may prefer to use explicit types for clarity.
- Especially when the right-hand side is a complex expression or function call.
- Inferred types are ubiquitous in idiomatic Kotlin code.
Conditions with "if"
Conditions with if
can be written as follows:
if (planet == "Jupiter") {
println("Radius of Jupiter is 69,911km")
} else if (planet == "Saturn") {
println("Radius of Saturn is 58,232km")
} else {
println("No data for planet $planet")
}
Each condition is followed by a block of code in curly braces. There can be any number of else-if blocks (including zero) and up to one else-block.
Note: In the else-block, the planet variable is included in the output string using string interpolation. To do so, you just prepend the variable with a
$
. More complex expressions must be wrapped with curly braces:"${user.name} logged in"
.
Equality and Comparison Operators
Kotlin’s operators to formulate conditions are the following:
Note that the comparison operators work on any Comparable
by using its compareTo
method.
Note for Java developers: In Kotlin, you use
==
where you would use equals in Java and===
where you would use Java’s==
.
Logical Operators
To build up more complex conditions from primitive conditions (using the operators above), Kotlin provides the standard logical operators:
Using these, you can combine multiple primitive conditions:
if (planet == "Jupiter" || planet == "Saturn" || planet == "Uranus" || planet == "Neptune") {
println("Your chosen planet has rings, typically made of rocks and ice boulders")
}
Summary
- Kotlin’s
if
conditions work the exact same way as in other languages like Java or C. - The logical and comparison operators are also known from some other languages.
- But in contrast to Java, Kotlin offers
==
for structural equality and===
for referential equality checks.
- But in contrast to Java, Kotlin offers
Arrays
Like lists and sets, arrays store multiple values in a linear data structure.
What is an Array?
An array is a basic data structure in all programming languages. It stores multiple elements by placing them consecutively in memory. This structure is represented in the following illustration:
What’s the Difference Between Arrays, Lists, and Sets?
Sets are easy to distinguish from both lists and arrays based on their special properties: no ordering and no duplicates.
To understand the difference between lists and arrays, we’ll have to look at the way their elements are stored and what implications this has for us as developers. While arrays store their values in one consecutive part of computer memory, list and set elements may be spread across memory. This has several implications:
- Arrays are a fixed-length data structure. This is because, after the array is initially created, the next consecutive place in memory may be taken by another value. Thus, no more consecutive values can be added to the array. Not being able to add or remove elements distinguishes them from mutable lists.
- Differences between arrays and read-only lists exists only on a lower level, i.e., in the exact API they provide, the storage structure in memory, and their resulting runtime performance.
Finally, there’s no differentiation between read-only and mutable arrays in Kotlin. Array elements can be overwritten but no elements can be added or removed, as they’re fixed in length.
Creating an Array
Kotlin’s API is very consistent when it comes to helper functions so the way to create an array should look familiar:
val priorities = arrayOf("HIGH", "MEDIUM", "LOW")
The arrayOf
function accepts any number of arguments and returns an Array<Something>
. In the example, it returns an Array<String>
(reads “array of string”).
Working with arrays
While you can’t add or remove elements from an array, you can access and manipulate all its elements using the indexed access operator:
val priorities = arrayOf("HIGH", "MEDIUM", "LOW")
println(priorities[1])
priorities[1] = "NORMAL"
println(priorities[1])
println(priorities.size)
Summary
Arrays are a linear data structure that store multiple values in memory sequentially.
- In contrast to sets, arrays are ordered, may contain duplicates, and store elements sequentially in memory.
- In contrast to lists, arrays are fixed-length because they store elements sequentially, and are always mutable.
- You can create arrays using
arrayOf(...)
.
Kotlin functions
Functions separate useful chunks of code into a named entity you can reference in your code. Along with variables, they are the absolute fundamental language construct to avoid code duplication.
Function Signatures
A function signature defines a function’s name, inputs, and outputs. In Kotlin, it looks like this:
fun fibonacci(index: Int): Long
This signature defines a function named fibonacci
with one input parameter named index
of type Int
and a return value of type Long
. In other words, you give the function an integer and get back a Long
. This function implements the well-known Fibonacci sequence.
Declaring a function
In a function declaration, both a function signature and a function body are required:
fun fibonacci(index: Int): Long {
return if (index < 2) {
1
} else {
fibonacci(index-2) + fibonacci(index-1) // Calls `fibonacci` recursively
}
}
The function body is a code block (thus surrounded by curly braces) and defines what the function does. The return
keyword defines the return value of the function call.
Calling a function
Once you have declared a function, you can call it by passing in a value for each required input parameter:
val output = fibonacci(6)
println(output)
This function call sets the index
parameter to 6
and runs the function with that input. For the output
variable, the Kotlin compiler infers the type Long
based on the function’s return type.
Function types
Functions have well-defined types in Kotlin. For instance, the fibonacci
function has type (Int) -> Long
, which means it accepts an Int
as input and returns a Long
. In other words, it’s “a function from Int to Long”. This concept becomes important once you get into functional programming in Kotlin.
Summary
Functions are possibly the most crucial concept to understand as they are one of the main building blocks in your code. Most day-to-day programming consists of adding, splitting up, removing, and otherwise working with functions.
- Kotlin uses the
fun
keyword to introduce functions. - A function consists of function signature and function body.
- The signature defines a function’s name, parameters, and return type.
- The function body defines what the function does.
- Functions in Kotlin have well-defined types that contain parameter types and return type.
What to learn next
Now that you have some basic understanding, you can move on to more complex concepts.
If you want to get up-to-speed fast, check out Educative's Kotlin Crash Course for Programmers. you’ll learn all the language basics including variable declarations, data types and the type system to conditions, loops, functions, and exception handling.
By the end of the course, you'll have the hands-on experience you'll need to make your own Kotlin apps.
Happy learning!
Continue reading about mobile app development on Educative
- How to develop your first an Android app with Kotlin
- Android Tutorial: How to Develop an Android App
- Flutter Tutorial: the beginner's guide to cross-platform apps
Start a discussion
Why do you want to be an Android developer? Was this article helpful? Let us know in the comments below!
Top comments (0)