Why you should completely switch to Kotlin

It’s time to start using a modern programming language

I want to tell you about new programming language entitled Kotlin and why you should consider it for your next project. I used to prefer Java, but over the past year I’ve found myself coding in Kotlin whenever possible, and now I really can’t think of a situation where Java would be the best choice.

It is developed by the company jetbrainsand the fact that it is these people who stand in the creation of such a set IDE, how IntelliJ and ReSharper, is fully reflected in Kotlin. He pragmatic and concisemakes coding a pleasant and efficient experience.

Although Kotlin compiles as in JavaScriptand soon in machine codeI will focus on its main environment – JVM.

So, here are a few reasons why you should completely switch to Kotlin (the numbering is random, in no particular order):

0# Interaction with Java

Kotlin on 100% compatible with Java. You can literally keep working on your old Java projects using Kotlin. All your favorites Java frameworks still availableand any framework you write in Kotlin will be easily adopted by your hard-nosed Java-loving friend.

one# Familiar Syntax

Kotlin is not some fancy language born in academia. Its syntax is familiar to any programmer coming from the area OOP, and may be more or less clear from the outset. Of course have some differences from Java, such as redesigned constructors or variable declarations val var. The snippet below provides most of the basic syntax:

class Foo {

    val b: String = "b"     // val means unmodifiable
    var i: Int = 0          // var means modifiable

    fun hello() {
        val str = "Hello"
        print("$str World")
    }

    fun sum(x: Int, y: Int): Int {
        return x + y
    }

    fun maxOf(a: Float, b: Float) = if (a > b) a else b

}

2# String interpolation

It’s as if a smarter and more readable version of the function has been built into the language String.format() from Java:

val x = 4
val y = 7
print("sum of $x and $y is ${x + y}")  // sum of 4 and 7 is 11

3# Type inference

Kotlin will infer your types if you think it will improve readability:

val a = "abc"                         // type inferred to String
val b = 4                             // type inferred to Int

val c: Double = 0.7                   // type declared explicitly
val d: List<String> = ArrayList()     // type declared explicitly

four# “Smart” transformations. (Smart Casts)

The Kotlin compiler keeps track of your logic and automatically performs type casting whenever possiblewhich means getting rid of checks instanceof and explicit conversions:

if (obj is String) {
    print(obj.toUpperCase())     // obj is now known to be a String
}

5# Intuitive equalities

You can stop explicitly calling equals()because the operator == now checks for structural equality:

val john1 = Person("John")
val john2 = Person("John")
john1 == john2    // true  (structural equality)
john1 === john2   // false (referential equality)

6# Default Arguments

There is no need to define multiple identical methods with different arguments:

fun build(title: String, width: Int = 800, height: Int = 600) {
    Frame(title, width, height)
}

7# Named Arguments

When combined with default arguments, named arguments eliminate the need to use builders:

build("PacMan", 400, 300)                           // equivalent
build(title = "PacMan", width = 400, height = 300)  // equivalent
build(width = 400, height = 300, title = "PacMan")  // equivalent

eight# When expression

As a replacement for the switch statement, a much more convenient and flexible expression is used when:

when (x) {
    1 -> print("x is 1")
    2 -> print("x is 2")
    3, 4 -> print("x is 3 or 4")
    in 5..10 -> print("x is 5, 6, 7, 8, 9, or 10")
    else -> print("x is out of range")
}

It works as an expression and as a statement, with or without an argument:

val res: Boolean = when {
    obj == null -> false
    obj is String -> true
    else -> throw IllegalStateException()
}

9# Properties

Custom set and get behavior can be added to public fields, which will allow us to stop cluttering the code with meaningless getters and setters.

class Frame {
    var width: Int = 800
    var height: Int = 600

    val pixels: Int
        get() = width * height
}

ten# Data Class

It is a POJO (Plain Old Java Object) with features toString(), equals(), hashCode() and copy()and unlike Java it doesn’t take almost 100 lines of code:

data class Person(val name: String,
                  var email: String,
                  var age: Int)

val john = Person("John", "john@gmail.com", 112)

eleven# Operator overload

The predefined set of operators can be overloaded to improve readability:

data class Vec(val x: Float, val y: Float) {
    operator fun plus(v: Vec) = Vec(x + v.x, y + v.y)
}

val v = Vec(2f, 3f) + Vec(4f, 1f)

12# Destructuring declarations

Some objects can be destructured, which is useful for iterating maps, for example:

for ((key, value) in map) {
    print("Key: $key")
    print("Value: $value")
}

13# Ranges

To improve readability:

for (i in 1..100) { ... } 
for (i in 0 until 100) { ... }
for (i in 2..10 step 2) { ... } 
for (i in 10 downTo 1) { ... } 
if (x in 1..10) { ... }

fourteen# Extension functions

Remember when you first needed to sort List in java? You couldn’t find a function sort() and as a result you had to learn about Collections.sort(). And later when you had to write String capitalized, it led to writing your own helper function because you didn’t know about StringUtils.capitalize().

If only there was a way to add new functionality to old classes; then your IDE could help you find the function you need with code completion. In Kotlin, you can do exactly that:

fun String.replaceSpaces(): String {
    return this.replace(' ', '_')
}

val formatted = str.replaceSpaces()

The standard library extends the functionality of the original Java types, which was especially required for String:

str.removeSuffix(".txt")
str.capitalize()
str.substringAfterLast("/")
str.replaceAfter(":", "classified")

fifteen# null security

Java is what we should call nearly statically typed language. It contains a variable of type String not guaranteed refers to String – she can refer to null. Even though we’re used to it, it defeats the safety of static type checking, and as a result, Java developers have to live in constant fear of bugs. NPE (NullPointerException).

Kotlin solves this problem by distinguishing between non-null) and nullable types. Types are non-null by default and can be made nullable by adding ? such as:

var a: String = "abc"
a = null                // compile error

var b: String? = "xyz"
b = null                // no problem

Kotlin forces you to guard against NPE whenever you access a nullable type:

val x = b.length        // compile error: b might be null

And while it may seem cumbersome, it’s actually quite simple thanks to a few features of Kotlin. We still have a smart cast that converts nullable types to non-null wherever possible:

if (b == null) return
val x = b.length        // no problem

We can also use secure call ?.which checks for null instead of throwing an NPE:

val x = b?.length       // type of x is nullable Int

Safe calls can be chained to avoid the nested if-not-null (if-not-null) checks we sometimes write in other languages, and if we need a default value other than nullthen we use the elvis operator ?::

val name = ship?.captain?.name ?: "unknown"

If none of this suits you, and the need for NPE is extremely high, then say so explicitly:

val x = b?.length ?: throw NullPointerException()  // same as below
val x = b!!.length                                 // same as above

16# Improved lambdas

It’s a good lambda system – it balances perfectly between readability and complexity, thanks to a well-thought-out design, with a simple syntax:

val sum = { x: Int, y: Int -> x + y }   // type: (Int, Int) -> Int
val res = sum(4,7)                      // res == 11

And here are the smart solutions:

  1. Method parentheses can be moved or omitted if the lambda comes last or is the method’s only argument.

  2. If we choose not to declare a one-argument lambda argument, it will be implicitly declared under the name it.

These facts combined make the following three lines equivalent:

numbers.filter({ x -> x.isPrime() })
numbers.filter { x -> x.isPrime() }
numbers.filter { it.isPrime() }

And it allows us to write concise functional code – just look at this beauty:

persons
    .filter { it.age >= 18 }
    .sortedBy { it.name }
    .map { it.email }
    .forEach { print(it) }

Kotlin’s lambda system combined with extension functions makes it ideal for creating DSL. Take a look at Anko as an example of a DSL that aims to improve Android development:

verticalLayout {
    padding = dip(30)
    editText {
        hint = “Name”
        textSize = 24f
    }
    editText {
        hint = “Password”
        textSize = 24f
    }
    button(“Login”) {
        textSize = 26f
    }
}

17# IDE Support

You have several options if you are going to get started with Kotlin, but I highly recommend using IntelliJwhich the comes bundled with Kotlin – its capabilities will demonstrate the full advantage of the fact that both the language and the IDE are developed by the same people.

As a small but revealing example, here’s what came up when I first tried to copy-paste Java code from Stack Overflow:

IntelliJ will notice if you paste Java code into a Kotlin file


Tomorrow there will be an open session. “Fundamentals of Classes and Objects”, in which we look at the design principles of classes and their implementation in Kotlin. Let’s understand how object-oriented programming works from the inside, create our own structures and look at the possibilities of the Kotlin language. Let’s design an object data model. Register link.

Similar Posts

Leave a Reply