Hi, friends!
I already mentioned that Kotlin is my favorite programming language. Even more, although most of my professional experience is in Java and I liked working in that language, I can bluntly say that I would never again choose to work in Java instead of Kotlin.
A lot has been said on this topic by different Kotlin fans. Still my blog would always feel incomplete in the future, if I left this out. So let me shortly present you my reasons:
- Kotlin was designed to write very concise code. That means, as a programmer you can very well express your intentions in the code without boilerplate noise, making the code readable and understandable.
- Kotlin differentiates between nullable and non-nullable types as a language construct. If you use it correctly, you can write much less error-prone code and save yourself from the ‘billion dollar mistake‘.
- The is no reason not to use Kotlin over Java. Kotlin is bidirectonally compatible with any Java code, so you can fully utilize all your Java skills and use all the libraries and frameworks you are already used to. You can even start using Kotlin in an ongoing Java project without converting any existing code. Start to write new classes in Kotlin instead of Java, and convert existing classe sone by one over time once you touch them to make changes anyway. This is possible because Kotlin compiles to the same JVM bytecode as Java. After compiling, there is no difference between classes writen in any of the two languages, and because of the great IDE support for Kotlin, even the context assistance will work perfectly between both.
-
Of course there are more reasons once you go into details (immutability, standard library), but the listed reasons (1) and (2) already give you a boost of productivity from day one, when you are just making your first steps in Kotlin. And reason (3) invalidates every counter argument I can think of.
Let’s have a closer look at those two claims.
Kotlin code is more concise
Take a typical class in Java, representing player characters in a game:
public class Character {
private String name;
private int level;
public Character (String name, int level){
this.name = name;
this.level = level;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public int getLevel(){
return this.level;
}
public void setLevel(int level){
this.level = level;
}
public void levelUp() {
// some logic here ...
}
}
What is the intention of the programmer who wrote this class? Not a lot, right?
- Having a class called Character that can be instanciated to create all the characters in the game
- A character has the properties name and level
- A character has a method levelUp with business logic
If you are a Java developer, the implementation seems pretty straight forward. But look closely! Isn’t there a lot of code that had to be written just because of the way Java works, but that has nothing to do with the programmer’s intention?
Do you spot it?
Let’s write the same class in Kotlin:
class Character(
var name: String?,
var level: Int?
) {
fun levelUp() {
// some logic here
}
}
Compare with the listed intentions again. It’s all there!
What’s the difference between the Java implementation and the Kotlin implementation?
In Java you had to read a lot of lines of code and then ignore them to find out which lines actually matter.
In Kotlin there is nothing else than the programmers intention!
How is that possible? In fact, Kotlin is exactly as powerful as Java. Any code you can write in Java is possible to write in Kotlin as well. But in Java, there is a lot of code that is there 90% of the time: The modifier “public” for classes and methods, the modifier “private” for properties, getters and setters, and the initializing constructor. We call this boilerplate code, because you don’t think about it, you just type it in everytime you write a new class.
In Kotlin this boilerplate code is invisible. You don’t have to write it and you don’t have to read it, so you can focus on the interesting code. But it’s still there! The Kotlin compiler will generate all these modifiers and getters and setters into the byte code, which means that the above Java class and the Kotlin class have the exact same byte code as output.
Of course, you can also write custom getters and setters and constructors with some logic; then you have to actually write them, in Kotlin same as in Java.
But since most of the time this code is boilerplate, it’s a huge gain to have it generated by the compiler for the default case.
It works like this:
- Classes and methods are public and final by default, unless declared otherwise
- Fields are private and have default getters and setters, unless declared otherwise
- In the top of the class, you write a constructor as part of the class declaration. Every argument of that constructor beginning with “var” or “val” is a declaration of a field at the same time, and the constructor will assign it’s arguments to the field, just like a default initialization constructor.
Up for a bonus? Let’s create a class Fighter that extends the class Character. First Java:
public class Fighter extends Character {
private final int attack;
public Fighter(String name, int level, int attack) {
super(name, level);
this.attack = attack;
}
public int getAttack() {
return this.attack;
}
}
Now Kotlin:
class Fighter(
name: String?,
level: Int,
val attack: Int : Character (name, level)
What is happening here?
- In Java, the field “attack” is read-only: There is only a getter, no setter. In Kotlin you achieve the same by using “val” instead of “var”
- The constructor of Fighter takes the arguments for it’s super class and then calls the constructor of the super class with these values. That’s done in Kotlin by not using val or var in the Fighter’s constructor. The “extends” is expressed by the colon “:”, and the call of the super constructor is expressed in the same line
- There is nothing left to write into the class body of the Kotlin class. Therefore the class body is just left out, no need to write an empty body like { }
Did I convince you that Kotlin is way more readable, because there is much less noise around the signal in the code?
Nullability in the type system
In Java, every object type can hold a null reference. I large code bases this leads to a lot of code like this:
if (playerCharacter.getName() != null) {
String initial = playerCharacter.getName().substring(0,1);
// ... do stuff with the initial
}
What’s the problem with that code?
- A lot of null checks in the code base add extra noise and distract from the business logic
- Missing null checks result in NullPointerExceptions, crashing the application
- Sometimes you think it’s not possible that a property hold the value null (i.e., the player character should always have a name after it is created). How do you deal with that? If you don’t check for null when using the value, you may make a wrong assumption and produce a bug. But checking for null, just to make sure, leaves the problem that there is no meaningful behavior of the application for that case. What should happen in the “else” there?
To help you out of this misery, Kotlin’s type system distingueshes between nullable and non-nullable variables. Look how we declared the properties of “character” to make it equivalent to the Java implementation:
class Character(
var name: String?,
var level: Int
)
The question mark declares the name as nullable. Since we don’t want to allow null as a value for a name, we just remove that question mark:
class Character(
var name: String,
var level: Int
)
Now the Kotlin compiler will prevent anybody from passing null as the value, and in any calling class we can rely that the name is not null.
On the other side, if we do use nullable types, the compiler will prevent the caller from using the value without handling null.
In my opinion, this feature alone makes it worth to use Kotlin over Java, since it prevents tons of potential bugs.