Software Development
Marcin Perlikowski
Marcin Perlikowski
Senior Java Developer
2022-05-18

Why Kotlin is awesome, but you will stay with Java anyway

If you are a Java developer, chances are you have at least some experience with other programming languages. Some of us started their programming adventure with another language like C/C++, JavaScript, C#, Python or maybe even something like Pascal or Basic. Some, though, started with Java and just never paid too much attention to other languages, unpleasantly remembering the one time when they needed to quickly code something on the frontend side.

Regardless of which group you belong to, there is a reason why you stay with Java. And I'm not blaming you. It has arguably the most developed, universal, and complete ecosystem in the entire enterprise world. The language has a nicely tailored set of capabilities, somewhere in the right zone between too much and too little. And new features are slowly but steadily being added, keeping it mostly up to date with newer trends in the programming world.

Do you know Lombok though? If you don't, I highly recommend trying. If you like it, then I have something just for you to try. A whole new language, that by its features makes Lombok obsolete. It's called Kotlin.

Kotlin? You mean the Android language?

Well yes, but actually no

Kotlin on Android got blessed by Google itself to the point of becoming the de-facto language of choice for the platform. This is not what I'll be focusing on in this article, but Android is indeed the place where I met Kotlin for the first time.

My work colleague was developing an app for a then-current project, on his own. Deadlines were approaching fast though, so I was delegated to help him meet them. Let me now transfer myself back in time to that moment. Aaaand... YUCK! Why is he using some weird language that sounds like a ketchup brand!? It looks awful!

Why is there "fun" written before every function? Like I don't already know what it is. Also, I'm already having fun with Java anyways. And where is the return type? At the end? Are you crazy? What's that, are you assigning something to a function? It doesn't make any sense! It all just looks like Java with extra steps! Wait, where is the class this method belongs to? Where did you hide it you ketchup-sounding, Java imitating excuse of a programming language? Oh no. Oh no, you didn't. IS THAT A GLOBAL FUNCTION? That's it, I'm done, I'm calling the police.

Spoiler alert: I didn't call the law enforcement. Whether I liked it or not, I had to adjust my Java-centric mindset to accommodate for another language. It won't be that bad though, right? It's still a JVM language, surely it's just a different Java. Maybe even with some cool extra features? Reluctantly, I started working on the project.

Java with extra steps

If Java is so great, why is there no Java 2? Jokes aside, That's what I thought to myself. I'll just pretend Kotlin is Java 2. New syntax and all, but I just need to learn enough of it to finish the project. Boy oh boy was I wrong.

After trying it for just a day or two, I quickly realized that both Kotlin and Java aren't that elastic. Trying to bend them towards each other inevitably ends with one of them snapping in half. It became obvious that Kotlin is a thing on it's own, and the fact that it works on a JVM means almost exactly nothing from a programmer standpoint. (On a side note, it can also transpile to JavaScript, or be compiled to a native binary).

Plan B then. Actually, get to know the language. Reading the docs for the first time sends some shivers through a seasoned Java programmer's spine. For example:

  • previously mentioned top-level aka global context
  • parameter and function return types specified at the end
fun sum(a: Int, b: Int): Int {
  return a + b
}
  • function body can be an expression (using equality sign)
fun sum(a: Int, b: Int) = a + b
  • if statement can provide a result
val y = if (x == 1) {  
  "one"  
} else if (x == 2) {  
  "two"  
} else {  
  "other"  
}

Ok, I'll just need to get used to it. Just a different syntax. What else do you have to offer, mister Kotlin?

value?.method() // execute if not null

Oh ok, getting rid of if (value == null), a point for you. What else you got?

fun check(list: List<String>, alternative: Boolean) = when {  
  list is LinkedList<String> -> print("linked")  
  alternative -> print("alternative")  
  list.size > 50 -> print("big")  
  else -> print("other")  
}

Hmm nice, could be handy to avoid if else blocks, still seems like a gimmick though.

object SingularObject: Counter() {  
  var a = 14
  fun test() = if (a > 10) "more" else "less"
}

Ok, that one looks actually useful, I like it! On the other hand, I can create a singleton in Java too. Maybe it won't be this elegant, but it's nothing really new. Any aces in your sleeve? Like, real heavy hitters?

var s: String = null // doesn't compile, non-null type

Wait... what?

The Billion Dollar Mistake

Imagine a codebase, where you don't need to worry about null safety. Imagine just taking it for granted that every reference actually contains something meaningful. Imagine being sure, that every null-related problem is dealt with in advance. Imagine no more. All references in Kotlin are not nullable by default. If you want to make it nullable, you have to consciously make that decision, and explicitly state it in the code:

var s: String? = null

I understand that you may be skeptical of the whole idea at this point. You are used to nullable references. You keep it in the back of your head while coding. You learned where you need to be careful. My thoughts exactly. Coming from Java, it felt weird at first indeed. Like, what's the point? It's not gonna magically make all related problems disappear. I'll just need to add "?" everywhere, sounds like a chore.

But I decided to dive deep into the language, didn't I? Let's have it your way mister Kotlin. I started making an effort to eliminate as many nullable variables, fields, and parameters as I could. Step by step, I learned to use language features that made it easier to eliminate nullable references, e.g. safe call "?." operator, elvis "?:" operator, delegated properties, "let" method, and more.

As time passed, I managed to get some classes to only contain non-null fields and method parameters. Basically, I knew that if a class was successfully instantiated, I could almost forget about nullability in method bodies. It was a bliss. With time, I appreciated this more and more. Ultimately though, I didn't think about it as a killer feature, Java still felt like home. Until...

The Comeback

The project was approaching the end. I got to know Kotlin more and more, and with this knowledge, the code became increasingly more tidy, readable, and concise. You could see the improvements with a naked eye in the commit history. The time has finally come, though. With unexpectedly fond memories of the new language, it was time to say goodbye and go back to the sweet comfort zone of Java. Or so I thought.

Do you know that feeling when you start to appreciate something the very moment it's gone? When you don't realise how much you rely on something until you can't use it anymore? It was the very best example of that feeling I probably ever experienced in my life.

As I got back to writing the code in Java, I was almost terrified by the lack of some features. It was like my brain subconsciously, wrongly retrofitted Kotlin features into Java. I experienced situations where I actually started implementing something, only to realize that it won't work in this language. Best case I could write it Kotlin-like, but it would be bulky, unreadable, and/or require too much boilerplate.

Null safety was of course the feature I missed the most. But I was surprised by how many smaller things became natural for me: named parameters, properties instead of getters and setters, "==" as equals and "===" as referential equality, qualified "this", extension functions, implicit singular lambda parameter, "_" for unused lambda parameters, data classes, scope functions, other Kotlin stdlib functions, operators and more. And the way it all nicely fits together. In comparison, Java felt... primitive.

It actually felt so bad that I started considering switching to Kotlin altogether. Theoretically, it's fully interoperable with Java, you can just add Kotlin support to an existing project and start writing new classes. Kotlin side knows how to "talk" to Java, and Java side doesn't even know that it's "talking" with another language. And after the compilation to bytecode, it does not really make any difference to the JVM.

Meet Java expert

Reality check

So what are you waiting for? If the language is as good as you say, just use it! Maybe not in existing projects though, I know that it should be interoperable, but mixing two different languages this way sounds ugly.

Ok, so for new modules - Kotlin it is. Or is it? You are working in a team. You need to consult them and convince them about the greatness of this new language. What? They don't like it? Sounds like they just don't want to put in the effort to learn it. You can't blame them though, you were skeptical at first too.

The project manager! Yes! He'll surely understand the great value Kotlin would bring to our team. Oh, the greatness that will come! -No -Wait, why? -The team doesn't know it. -They'll learn! -They don't want to learn. -You can make them! -They don't need to learn. -I mean, that's true, but think about the possibilities! -Yea, what about you think about the problems first.

The legend says that there exists a project. A project that's big and complex, but nicely written in every part. A project, where all the developers are in unison about used solutions. Where new functionalities just smoothly flow from the programmer's keyboards. Where bugs are rare and easy to fix.

Have you seen a project like that? I haven't. Some came close, but most of them are a big legacy code mess. And if they aren't, they'll probably become one at some point in the future. Now imagine throwing in another language into the mix. It introduces new ways to make mistakes. It requires developers to know what they are doing. It's a risk, to say the least.

Now also consider developer rotation. People come and go. Will you make every new developer learn a whole new language? No, that's counter-productive. Will you hire Kotlin developers in the first place? Good luck with that, hiring a good Java dev is hard enough.

People have tried. I have to say that I don't agree with most of the allegations in that article. There is some valid criticism in there, but I think they didn't use Kotlin enough to actually understand "the Kotlin way". Many commenters under that article seem to think similarly.

That doesn't matter though. I bet this would happen in your project too. "Tried it, didn't like it". You won't make them spend more time on it. You won't make them try again. You won't make them give it another chance. And from a practical standpoint, they may be right. Java is just so popular, that using anything else on the JVM seems redundant.

Why this article then?

You just spent a considerable amount of time writing an article, that seems to not have a point. Why would I try learning a language, if you say that it's pointless anyway?

Well, I don't think it's pointless. I still think that Kotlin is great. I still want to actually use it (and I actually do for my private projects). If I could, I would just switch to it and forget about the limitations of Java. But the current reality says that I can't. And I want to try and change that.

My intention for you, dear reader, is to at least entertain the possibility of coming out of the cozy Java comfort zone. Because maybe, just maybe, you will love Kotlin as much as I do. And if you do, that's one more Kotlin-knowing developer on the market.

Read more:

The Best Type of Projects for Java

3 Common Challenges of Software Product Development for Startups

The Right Way to Find Top Java Developers