DEV Community

Cover image for How to learn Kotlin: A guide for beginners & Android developers
Hunter Johnson for Educative

Posted on • Originally published at educative.io

How to learn Kotlin: A guide for beginners & Android developers

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:

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
}});
Enter fullscreen mode Exit fullscreen mode

Kotlin:

view.setOnClickListener { // Do whatever you want to }
Enter fullscreen mode Exit fullscreen mode

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

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")
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 to var 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 over var 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Two things to note:

  • The e in both values denotes exponentiation, for instance 10e3 == 1000.
  • In order to denote a Float value, you have to add the f suffix. Otherwise, Kotlin infers Double 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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Summary

Here’s what you should take away from this section:

  • Kotlin has Byte, Short, Int, and Long as basic types for integer numbers.
  • Kotlin uses Float and Double for floating point numbers. A Float is denoted with a trailing f, as in 17f.
  • Kotlin has Char to store single characters and String to store strings of text.
  • Kotlin’s basic types map to Java’s primitive types when targeting the JVM (and String maps to String).

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
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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")
}
Enter fullscreen mode Exit fullscreen mode

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:

Kotlin operators

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:

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")
}
Enter fullscreen mode Exit fullscreen mode

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.

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:

Arrays

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.

Kotlin

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")
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
 }
}
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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

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)