Skip to content

Kotlin Primer

Introduction

Let's learn Kotlin from a Java point of view. We'll start by looking at some basics of Variables, Values, Classes, Properties and Constructors.

Note

I assume you know Java well, as I compare the languages and wave my hands at parts that are very similar.

I remember the way I felt when Java came out. There was this feeling of freedom using Java after using C++ for so long. I feel the same way switching from Java to Kotlin...

Let's start by taking a look at the very basics of Variables, Values, Classes, Properties and Constructors.

A Note on Nulls

While you're reading this, you'll likely think "why didn't he use null instead of dummy values?"...

Nullability is a pretty big concept and I knew this article would be pretty long to start with, so I'm punting it down the road a wee bit. But don't worry... I'll get to it... It's quite important!

Main Functions

Kotlin has "main" functions just like Java. You'll most likely use Kotlin in environments like servers or Android applications that don't need a main, but they're useful for examples.

If you don't need any command-line arguments:

fun main() {
    println("Hello, World!")
}

If you want command-line arguments, you can use an explicit Array (more on that and joinToString() later). I'm passing A B C to Kotlin Playground for this example.

fun main(args: Array<String>) {
    println("Hello, World!")
    println(args.joinToString())
}

Note

The embedded version of Kotlin playground doesn't support passing arguments to the main, but you can click the "Open in Playground" link and pass arguments in the "Program arguments" box at the top. I won't be using arguments for any examples other than these two, so you'll be able to full execute all other examples here in these pages.

or you can use a varying-length argument list (more on that and joinToString() later). I'm passing A B C to Kotlin Playground for this example.

fun main(vararg args: String) {
    println("Hello, World!")
    println(args.joinToString())
}

Yay! No Semicolons!

Ding, dong, semicolons are dead! Well, not dead, just not as required as in Java. You can still use them to separate statements, but I don't recommend it. Give yourself a little time to get used to it, and you'll add 5 more years before you get carpal-tunnel syndrome. At least according to the science I made up in my head.

(I do find myself forgetting semicolons when I have to write Java code... But I don't do that often anymore...)

Variables and Values

In Kotlin, we explicitly state whether a local or member of a class can be modified. We do this by specifying var or val to define a variable or value.

fun main() {
    var x: String = "Hello"  // note - initializer is redundant
    val y: String = "Message"

    x = "aaa" // just fine; can change the variable
    y = "bbb" // will not compile!!! can't change a "val"

    println(x)
    println(y)
}

This example will fail to compile! We told Kotlin that y is a val, meaning it should be read-only. Change it to a var and try running.

The initializer = "Hello" for x is redundant. We never read x before we assign it We could instead write:

fun main() {
    var x: String
    val y: String = "Message"

    x = "aaa" // just fine; can change the variable

    println(x)
    println(y)
}

Type Inferencing

But things get even better. Kotlin loves to infer types so you don't have to write as much code. For example:

fun main() {
    val x = "aaa"
    println(x)
}

The expression "aaa" is of type String, so kotlin knows that the value x can be a String and infers the type.

Everything is Public and Final

First, the good news...

All types, functions and properties are public by default. I think this was a great choice, as I'm a big proponent of keeping things accessible unless there's a really strong reason not to (that reason is usually a sensitive algorithm, such as a security feature). public here means the same thing as in Java; any class can access public types, functions and properties.

However...

All classes, functions and properties are final by default (unless explicitly marked as open, abstract or sealed), or being functions/properties defined inside an interface). Interfaces are always non-final (as a final interface wouldn't make sense...)

Here comes the rant!!!

This was a horrible design choice, IMNSHO. This means you cannot create subclasses, or override functions or properties unless the parent explicitly says so. Unfortunately the designers of the language took advice from "Effective Java" (which says to only make non-final if you intend people to extend) a little too far.

I've come across far too many cases where a library doesn't let you extend something that has gotten in the way. I believe in the Open/Closed principal - open for extension, closed for modification of its guts.

Rant over... you may continue with your lives...