DEV Community

Cover image for 10 reasons to switch from Java to Kotlin right now!
v-aksenov
v-aksenov

Posted on

10 reasons to switch from Java to Kotlin right now!

My name is Viacheslav Aksenov, I am developer of big and complex backend systems. I started from Java 7, than upped to Java 8 and sometimes Java 11 for developing. Last year I Writing all new code on Kotlin and this is totally changed my life. I didn't know before that Kotlin can be used for backend developing and more than - for backend developing using all top Java framework like Spring, Jackson, etc.

So I want to share my happiness with you and give 10 reasons of why you should to take a see on Kotlin and integrate it to your projects.

1. Null safety

In Kotlin, it is required to explicitly indicate whether a particular method can return null or not. Thus, we can assume that all data is already wrapped in an analogue of Optional. And NullPointerException will be so rare by you that you will miss it.

fun saveReviewNullable(r: Review): Review? = reviewRepository.save(r)

fun bar(r: Review) {
    val savedReviewNullable: Review = saveReviewNullable(r)!! // can throw NPE. Not safety
    val savedReviewNotNull: Review = saveReviewNullable(r) ?: Review() // safety way
}
Enter fullscreen mode Exit fullscreen mode

2. Highlighting the main constructor

The bottom line is: there is a Primary constructor and a Secondary constructor. Helpers are required to call the main one as a constructor of the parent class.

class Cat(val name: String, val color: String, val height: Int) {

    constructor(name: String) : this(
        name = name,
        color = "fixed color",
        height = 10
    )
}
Enter fullscreen mode Exit fullscreen mode

3. Initialization and logic of working with DTO classes

The example is hackneyed, but as clear as possible.

data class Cat(val name: String, val color: String, val height: Int)
Enter fullscreen mode Exit fullscreen mode

And now it's the same in Java:

public class Cat {
    private final String name;
    private final String color;
    private final Integer height;

    public Cat(String name, String color, Integer height) {
        this.name = name;
        this.color = color;
        this.height = height;
    }

    public String getName() {
        return name;
    }

    public String getColor() {
        return color;
    }

    public Integer getHeight() {
        return height;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Cat cat = (Cat) o;
        return Objects.equals(name, cat.name) && Objects.equals(color, cat.color) && Objects.equals(height, cat.height);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, color, height);
    }
}
Enter fullscreen mode Exit fullscreen mode

It seems to me that even comments are superfluous here.

Data class pointers in Kotlin by default imply getter, setter (for var fields), equals, hashcode, toString for all fields. If you want, you can override each of these methods in your own way, but this is rarely required.

class Cat(val name: String, val color: String, val height: Int) {

    override fun toString(): String = "overridden toString"
}
Enter fullscreen mode Exit fullscreen mode

4. Explicit declaration of mutable and immutable fields - var/val

Another advantage: in Kotlin, you get pretty simple and elegant constructs. If you want the dto field to be changeable, then var is used to declare it. Then the setter method will be created and the field will not be final.

And if you need to make the field immutable, you should use val for the declaration. It looks very nice and simple. Plus no need to follow up on helper methods.

Example: the color and height fields can be changed after creation, and the name can only be changed when the object is initialized:

data class Cat(val name: String, var color: String, var height: Int)
Enter fullscreen mode Exit fullscreen mode

5. Collections are immutable by default

What appeared in Java a little later has long been in Kotlin - creating collections is immediately immutable.

val list = listOf("one", "two")
val map = mapOf(1 to "one", 2 to "two")
val set = setOf(1, 2 ,3)
Enter fullscreen mode Exit fullscreen mode

Any changes to these collections will create a new immutable collection after conversion:

val list = listOf("one", "two")
val list2 = list.plus("three")
Enter fullscreen mode Exit fullscreen mode

But you won't be able to change any element separately. For classic mutable collections, explicitly mutable analogs are used:

val list = mutableListOf("one", "two")
val map = mutableMapOf(1 to "one", 2 to "two")
val set = mutableSetOf(1, 2 ,3)
Enter fullscreen mode Exit fullscreen mode

6. Extensions.

For example you have really uncomfortable model from other API, that store data in really high nesting. In Java you would need to write converter from one useless model to usefull one.

In Kotlin you can just add Exctension for any class, even for class from external libriary and use it as you want:

data class SomeBadModel(
    val innerModel: EvenBadModel
)
data class EvenBadModel(tons of fields)


fun SomeBadModel.doGoodStuff(val any: Any?): Any? = usefullLogicHere
Enter fullscreen mode Exit fullscreen mode

7. Working with complex classes using primitive methods

An advantage of Kotlin, which I never cease to rejoice in is the ability to use operators for basic operations on complex classes. If you need to add BigDecimal numbers, you take them and write them through plus. You do not need to explicitly call the method on the first term.

val a = BigDecimal(1)
val b = BigDecimal(2)
val sum = a + b
Enter fullscreen mode Exit fullscreen mode

In Java, you need to call a special method:

BigDecimal a = new BigDecimal(1);
BigDecimal b = new BigDecimal(2);
BigDecimal sum = a.add(b);
Enter fullscreen mode Exit fullscreen mode

It's the same with arrays: if you want to remove an element from a mutable array, you write the array minus this element. And if the element is present, then it will be removed.

val list = listOf("one", "two") - "one" // list = ["two"]
Enter fullscreen mode Exit fullscreen mode

8. Possibility of one-line methods really on one line

If the method is simple and consists of one operation or a chain of operations written in one line, then it is not necessary to write curly braces and return. You write directly:

fun getReviewByTitle(title: String): List<Review> = reviewRepository.getAllByTitle(title)
Enter fullscreen mode Exit fullscreen mode

Instead of Java option:

public List<Review>(String title) {
        return reviewRepository.getAllByTitle(title);
    }
Enter fullscreen mode Exit fullscreen mode

9. Scope functions

Interesting moves towards functional programming in the spirit of highlighting context: lambdas can be rotated as you like.

There are let, apply, also, with, run functions. Because of their abundance, at first the question arises: what is suitable for a particular case. But when you get used to it, it becomes unclear how you used to live without them.

A simple example: take the result and process it somehow:

fun save(review: Review): Review = repository.save(review)
fun bar(r: Review) = saveReview(r).let { it.comment + it.date}
Enter fullscreen mode Exit fullscreen mode

Or initialize the object and additionally initialize its var fields:

class Cat(val name: String, val height: Int) {
    var color: String? = null
}

fun bar() = Cat("Fred",10).apply { color = daoService.getPopularColor() }
Enter fullscreen mode Exit fullscreen mode

10. Easy to integrate into an existing Java project.

If you are just looking at Kotlin for the backend, then keep in mind that in the environment that launches your project in Java 8, you can run a compiled project in Kotlin without dancing with a tambourine. Yes, on the same jvm, on the same environment and with a minimum of effort.

It was a discovery for me that even within the same application there can be classes in Java and Kotlin. All the magic happens at compile time. Depending on the settings, you can specify what to build first: Kotlin classes or Java classes.

Compilation of Kotlin sources into byte code from Java LTS - 8, 11 and (so far experimental) 16 is now available.

Conclusions

Someone might say that this is sugar sugar and they will be right. But on my own I will say: if a large number of boilerplate things are included in the language, and you do not need to constantly think about them, the development process becomes simpler, the number of errors is less. But you need to think about the code style more often, because without it you can screw a lot.

Now I still continue to write and see code in Java, but in 99% of cases this is due to educational programs in which I take part as a mentor.

I advise everyone to try it - at least on a pet project to understand whether the Kotlin paradigms are right for you or not.

Discussion (13)

Collapse
190245 profile image
Dave

This interests me for a number of reasons (that I can happily get into, if appropriate).

I was going to pick through your list, and post a response from the Java perspective, but lets cut to the chase:

if a large number of boilerplate things are included in the language, and you do not need to constantly think about them, the development process becomes simpler, the number of errors is less.
Enter fullscreen mode Exit fullscreen mode

Assuming that is your motivation for the list, Java boilerplate can be removed in 3 ways:

  1. Frameworks (eg, Spring)
  2. Lombok / later versions of java (where data classes are supported, and val/var are part of the language)
  3. Custom annotations.

Then there's this:

But you need to think about the code style more often, because without it you can screw a lot.
Enter fullscreen mode Exit fullscreen mode

Forgive me, but code style is an internal discussion, and a document. That produces a formatter (IntelliJ will work with an Eclipse formatter export, etc). That even deals with your "one line method" claimed benefit (our formatter forces methods to one line, if the body of the method has one line, overriding our line length constraints).

I genuinely get the impression, and I'm sorry in advance if it's incorrect, that there's motivated reasoning behind this post - you like Kotlin, therefore everyone should at least try it.

Since I manage a Java development team, and one of my developers semi-frequently (and half jokingly) says things like "this would be easier in Kotlin" - I'm genuinely interested to hear concrete business benefits to using Kotlin over Java in the development cycle. My starting premise: more developers understand Java than Kotlin, so hiring people is easier.

Collapse
kgunnerud profile image
Kenneth Gunnerud • Edited

About the same reasoning I have. We use Spring + Lombok and it solves a lot of the pain points (although some remain). Kotlin does enforce better guard rails (null-handling for example), but at what cost?

When it comes to features that Java has implemented after others have shown how it can work (e.g. instanceof, loom vs coroutines (I know, not out yet), record types) I do have to say I like the Java version better? Might be a preference but it seems that Java is slowly catching up while Kotlin in the near future has to make some hard choices on how they wish to do things (ref the reddit article posted earlier highlights this in a good way).

Although, your post about LTS further up I am less sure about but I guess that also might depend on context. We run Java 16 just fine in production for mission critical applications and have no issues with it. No service agreement either, as long as we have a robust set of tests and can deploy at will with good monitoring, we have seen no issues with this over a long period of time (not always Java 16 but keeping us at the latest version).

I know very little about the practical meaning with LTS (I've understood its more about backporting bux fixes from latest) but I might be wrong here so please correct me if I am.

Collapse
190245 profile image
Dave

The "Kotlin cost" - from my perspective, is that I already pay Java developers. Why do I need them to go through the cognitive complexity of learning a new syntax, if we're just going to run it inside a JVM anyway?

That, and Graal looks really interesting, as soon as MS sort out SQL JDBC compatibility, though I know that's on their roadmap. I haven't a clue what native compilation would look like in Kotlin, and the benefits of native compile far outweigh the niceties that Kotlin may bring to the table... though, that's diverging from the topic a little... and Graal will likely force us to stay a little behind the JVM release cycle.

LTS - for us, at least - isn't about "can I run this in Production." It isn't even about the level of support offered. It's more about buying time to weigh up options when avoiding vendor lock-in situations.

For an example there, we still have a large number of projects that run in a very specific build of Java 8. At least one of them, for reasons I haven't yet fathomed, will happily compile in 9... but then it refuses to run. Even when you ask javac to give Java 8 compatible bytecode. Then, during the our future migration of that project, I need to worry about reflection API changes within the JVM over time, etc etc. Plus we have dependencies to worry about, like our Tomcat version and which Servlet API it's using, or can work with and not break other dependent projects...

Sometimes, it simply makes more sense for legacy projects to stick with an LTS. Then when that's approaching EOL, we can look at "is it more beneficial to just bin that project, and re-write it?" - which also opens options for "should we do this in Kotlin/dotnet/Java/JS/C++ etc and which of those options gives the best ROI? Which team has the skillset to do that before EOL? What new features of these languages do we want to benefit from?"

Equally, our build pipeline is really simple to switch between Java versions and see if a project works in a different version... but that's why, ultimately, the language & version is a decision based on what's best for the business, not what makes developers feel cozy & warm (there's better ways to make developers happy, rather than chasing the latest tech all the time).

I mean, I still read the JVM release notes and geek out about upcoming changes, and share those around the business...

Thread Thread
kgunnerud profile image
Kenneth Gunnerud

Jepp, and as Java gets more features anyway, many things will get better. So personally we have not switched although I do from a developer perspective like what Kotlin has done, but from a broader view we have not swapped although some people want to, with the same reasoning as you have combined with the fact that Java is moving along rather fast now (and many of the small things can be fixed with frameworks/libs anyway).

Okey, I understand the premise with LTS for your sake then, thanks for clearifying.

Collapse
robole profile image
Rob OLeary • Edited

Interesting read. I understand the benefits of Kotlin, but the payoffs don't seem to be big for developers who have experience with Java already. What people forget that there are many JVM languages such as Groovy, Scala, Clojure...etc, and I think that diversity is cool, but most of these languages are offering something quite different than Java e.g. Groovy is dynamic and good for scripting..etc. Kotlin seems the most like Java, but it's biggest selling point is less boilerplate.

What is different than the other JVM languages is that Kotlin has the most mainstream traction. This seems to be mostly because Google promotes it for Android development. I was learning some Android programming and I found it muddied the waters that tutorials and examples are mix of Java and Kotlin. If you consider that Java adopted some features from other languages in later versions, I feel it hurts education and adoption in the long-run if there is a migration. If you learn Java in university and companies are mostly using Kotlin, it's making it a longer path for people starting off.

I haven't delved into Kotlin, so I don't want to show bias, but based on what I know now - I would learn Scala over Kotlin. You gain more from delving into a different programming paradigm and using a language that has different applications.

Collapse
kgunnerud profile image
Kenneth Gunnerud

Great post, and although I love what Kotlin has done, what are your thoughts about the future?

For example, a language that says one of its features is that its very similar to Java but considering that Java is also up'ing its iteration cycles, how will this affect Kotlin in lets say, 2 years?

A great post that puts it in a bit of perspective: reddit.com/r/java/comments/ndwz92/...

I don't advocate in absolutes, but thinking about what your choice given your context and also taking a look into the glass ball might be a good approach.

Collapse
jmfayard profile image
Jean-Michel Fayard πŸ‡«πŸ‡·πŸ‡©πŸ‡ͺπŸ‡¬πŸ‡§πŸ‡ͺπŸ‡ΈπŸ‡¨πŸ‡΄

I've read this insightful comment about what happened when Java adds new features that were in Kotlin only before. New features released in Java is a good thing IMHO, it means the whole ecosystem progresses. But for people to actually use the new features, they have to be willing to update the SDK. But it turnns out Java programmers are very wary of updating the SDK. Java 16 is released but we are still in the middle of the migration from Java 8 to Java 11.

So Kotlin is perhaps doomed in the long term, but in the long term we are all dead!

Collapse
kgunnerud profile image
Kenneth Gunnerud • Edited

I agree if the premise is SDK 8/11 or Kotlin forever, but at least the place I have been (mostly public sector) has seen a shift into product teams with autonomy, so updating to a new SDK has and is not an issue.

Also, if the issue is that companies refuses to upgrade the SDK, can that be applied to Kotlin as well (over time)? Or is every part of a company that uses Kotlin always able to upgrade but those that use Java are not?

I love kotlin as much as the next guy, it's just that every post I see about Kotlin vs Java is about the small stuff (which of cource comparing Java 8 vs Kotlin leaves java with a lot of bruises), but I never see any discussions about the negatives? Cause if I am to suggest to a customer, a client or just my co-workers that we should change, it also has to include the down sides and usually with a timeframe more than a year ahead when picking a language for a product. And if the premise is that people don't upgrade SDK, the same can just as much be applied to Kotlin and then you gain little. Something along the lines of: Fix the culture before you try fix it using technology.

Edit: And I agree, I love that people see Java and think in the lines of: "We can do this better!", such as Kotlin did. And as we see now, the ecosystem and Java is also better off. Java has its weaknesses and luckily some of them are being adressed. This post is rather good if you wish to see how the JVM team is thinking about changes: blogs.oracle.com/javamagazine/java...

Thread Thread
jmfayard profile image
Jean-Michel Fayard πŸ‡«πŸ‡·πŸ‡©πŸ‡ͺπŸ‡¬πŸ‡§πŸ‡ͺπŸ‡ΈπŸ‡¨πŸ‡΄ • Edited

Updating Kotlin is not the same as updating Java. In the second case you upgrade the virtual machine and hope for the best, which has been sometimes painful in the past, while when you update Kotlin you are still compiling bytecode for the same virtual machine, so you keep the same infrastructure.

And yes Java being a very mature technology has pros over Kotlin, for example the compiler is faster and static analysis tool are better. And hiring Java developers is easier, outside of the Android world, you may have to be OK with developers learning Kotlin on the job.

Thread Thread
kgunnerud profile image
Kenneth Gunnerud • Edited

Yes, I agree with those premises. although I wish it came more apparent in the discussions between Java or Kotlin

Thread Thread
190245 profile image
Dave

@jmfayard
you upgrade the virtual machine and hope for the best

That sounds painful to even read. Please tell me someone you work with has read, understood, considered and then tested the upgrade path, before just "hoping" it will work...

Collapse
190245 profile image
Dave

Who told you that people are wary of updating Java?

I mean, I wouldn't want to use something in Production that didn't have an LTS agreement behind it, but that's not only limited to Java.

The main issue, is the security manager and Modules when moving through Java 9/10... but maintaining legacy projects always has legacy problems. All our newer projects are in Java 11 when deploying, or 14 during development (Maven profiles...). When we hear the next LTS release beyond 11, that will be our default - the next morning (and CI/CD will log tickets for projects that fail to build for some reason).

Challenging, yes, but wary?

Collapse
shvahabi profile image
Ψ΄Ψ§Ω‡Ψ― • Edited

Actually all these stuff adopted from father of Kotlin which is Scala. But this article still gives a very good gathering of Scala excellence over Java, and hence so valuable to me to the point that gave me a brilliant moment of enlightenment.

Anyway I encourage the author to write another article named such as "10 reasons to switch from Kotlin to Scala right now!" and select 10 (from at least 100 one of) features of Scala not available in Kotlin from it's advanced type system targeting soundness; and new metaprogramming capabilities come from any source code's Tasty IR; and functional effectless programming combined with actors for uncomplicated asynchronous microservice implementation; also mentioning ScalaJS to replace Kotlin and JavaScript for web and ScalaJVM plus Jetpack Compose to replace Kotlin for Android.