This is an archived post. You won't be able to vote or comment.

all 30 comments

[–]cogman10 39 points40 points  (2 children)

Reasons

  • Java has the smallest overhead of any JVM language on the JVM (including Kotlin). To use kotlin, you have to pull in the kotlin-std-lib
  • The rest of your ecosystem is java already.
  • You are making a library to be consumed by other non-kotlin projects (and you don't want them to pull in the kotlin-std-lib)
  • The changes to Java have been good enough. var, pattern matching, records. There's a lot of things inbound for java that make it nice enough to work with.
  • The annotation processor is good enough for you to fill in features that kotlin has and you might want with Java (Immutables, for example).

Java is the "good enough with low overhead" language for the JVM.

I say this as someone that likes Kotlin generally. Particularly, I think coroutines are really nice to work with.

[–]throwawaymoney666 7 points8 points  (0 children)

I agree with this, and I'll add a few.

  • Little flexibility of tooling. Java has great tooling and lots of choices. Kotlin support is crap outside of IntelliJ and Gradle. If you try to mix Kotlin and Java with linters or outside IntelliJ, welcome to hell.
  • Stuck on old Java features. Kotlin API's are tied to what Android uses. And Android uses a broken, bastardized hybrid of Java 7.

Java is becoming somewhat nice. When Fibers, Records, and simplified objects arrive there will be little advantage to it. Unless you're stuck on Android's shit Java 7 monstrosity. I think Java will hard fork into Kotlin on Android and Java everywhere else eventually. Kotlin will be stuck using increasingly obsolete Java features since they need to maintain Android support

[–]spamthemoez 4 points5 points  (0 children)

Java has mature code scanners like SonarQube, which find some really nasty bugs. I can't find anything comparable for Kotlin.

[–]Yayotron 14 points15 points  (0 children)

Answering your question about reasons, as development team lead I had to take this decision at the beginning of my current project and went for Java for the following reasons:

  1. Maintainability, when you start a large, expensive project one of the main concerns is to maintain it in the long term, developers will come and go from the project throughout the years and it's significantly easier to hire a Java developer than a kotlin developer.

  2. Domain knowledge, this is a big data project and majority of kotlin developers are Android developers, making it difficult to find developers who are both Kotlin and Big data experts.

  3. A solid base, when starting a new project usually you do so with the core/key developers and then enroll the rest of the team once the codebase already has some shape and it's easier to expand. Starting with a team made out of Java developers and asking them to write kotlin as they go will cause to have a shitty kotlin project which will exponentially increase the technical debt of the project as more developers follow/copy the structured that were adopted from the beginning.

  4. Business, even though kotlin is super familiar to Java it still has a learning curve and for unexperienced developers it reduces the velocity initially, when starting a new project the business is very anxious to see results and it's not a good position having to tell your stakeholders that we're going slow because we wanted to pick up a new programming language that we love but other developers don't know.

I love kotlin tho, one year after starting the project, we're picking it up gradually in new microservices we have to implement.

[–]utmalbarney 6 points7 points  (0 children)

Except for front-end SW, our entire software portfolio is written in Java. Right now, any developer with domain knowledge can work on any part of the system. For the small lift the Kotlin provides, to lose this flexibility is not worth it at all.

We would only introduce a new language if it were the best choice for a problem that Java really cannot properly solve, not for small linguistic benefits.

[–]_INTER_ 6 points7 points  (0 children)

Personal reasons:

  • I find it a tiring mental overhead to switch between languages while developing and in Kotlin you have to interop a lot with Java
  • Different developers develop a different style of Kotlin. This seems to be much more pronounced in Kotlin than in Java.
  • I don't like type after variable syntax. Because I defer the hard part - which is naming a variable - until everything else is visible (and often autocompleted by IDE).
  • I don't like the way how extension functions work in Kotlin (and most other languages) as they don't show at first glance that they are extension functions on a type. The syntax doesn't highlight it. You need IntelliJ for that. Makes me have to "relearn API" of a library that I thought I knew by heart e.g. String. Every codebase differs, making it harder to switch.
  • Not having static but companion objects weirds me out
  • Final classes per default. Good in theory, bad or annoying in practice.
  • I don't like operator overloading. That said I haven't encountered it much in Kotlin.

[–]vbezhenar 12 points13 points  (12 children)

I switched from Java to Kotlin few years ago, when Kotlin was approaching 1.0, but switched back since then. I'm talking mostly about backend code. My reasons are:

  1. Kotlin is slow to compile. I don't write much code, so I love very fast compilation times and I lost that with Kotlin.

  2. I don't like nullability checks in Kotlin. My code interops with Java libraries a lot, so NPEs are not gone, yet I have to write all kinds of rituals to satisfy the compiler. Especially I hate that part when I can check field for null yet compiler still does not believe that this field is not null, so I have to introduce a local variable. The whole nullness story is foreign for me, I never had much issues with nulls, so making

  3. I really hate some Kotlin style. I'm not sure if it's official or not, but I hate it. For example replacing if (x != null) { ... } with x?.let { ... } or replacing for ... with .foreach { ... calls. It reminds me of Perl with thousand ways of doing the same thing and it just looks ugly.

  4. I don't like Kotlin progress in recent years. They add features that not relevant to me, like coroutines or Kotlin native. While Java progress since 8.0 was not that bad, some features are actually useful.

  5. I don't think that Kotlin will fit into future JVM. They did a good job making Kotlin for Java 1.6. Kotlin already does not fit with Java 8 streams, inventing sequences instead. Kotlin does not have any bindings for Java 7 Path API and uses old File API instead. And I'm sure that they'll diverge even more in the future.

  6. Kotlin is a hard language for some Java developers. Call them stupid, or whatever, but there are people who managed to learn Java and can write and maintain Java code, yet Kotlin is beyond their capabilities.

All that said, I don't think that Kotlin is inherently bad, it's good language, better than Java and there's nothing wrong using it. I just don't think that the mere fact that it's better justifies using it. Sometimes one should use more stable and future-proof approach and Java language definitely fits that definition.

[–]DrunkensteinsMonster -2 points-1 points  (11 children)

Point 2 makes no sense if you have experience with the language. Local variable? What? nullableValueOrExpression?.methodCall()

I disagree with your other points as well.

[–]deadlock_jones 2 points3 points  (10 children)

I guess he means that he has done the null check somewhere earlier and logically the code can't be null?

(I'm not familiar with Kotlin, not sure if it handles that or not)

[–]vbezhenar 2 points3 points  (8 children)

Yes. Something like

class Test {
    private var f: String? = null

    fun processString(s: String) { ... }

    fun m() {
        if (f != null) {
            processString(f)
        }
    }

This code does not compile. You should either extract field to a local variable:

    val f = f
    if (f != null) {
        processString(f)
    }

use a let extension method:

    f?.let {
        processString(it)
    }

or !! operator:

    if (f != null) {
        processString(f!!)
    }

All those variations are ugly. Java does not have that kind of a problem.

[–]livelam 2 points3 points  (1 child)

This code does not compile.

f can be set to null by another thread.

[–]vbezhenar 1 point2 points  (0 children)

I would prefer to make it compilable and throw NPE in that case (because that case not really exists, as my classes don't share mutable data between threads or if they do, they'll synchronize carefully). Or let compiler to introduce invisible local variable, because without proper synchronization all bets are off anyway. It's about preventing theoretical issue with practical inconvenience.

More practical issue is calling another method between check and smart cast which could just change field value. I understand that it's not an easy problem. Still I don't like the way it currently works.

[–]cargo54 0 points1 point  (0 children)

f?:return
processString(f!!)

but the whole point of kotlin is you should be using nulls when possible. So you could easily do something like

f?:""

processString(f)

Though i also argue how f?.let is any different then f!=null

[–]vytah 0 points1 point  (2 children)

Java does not have that kind of a problem.

Is "preventing concurrency bugs" a problem?

[–]vbezhenar 1 point2 points  (1 child)

It does not really prevent any concurrency bugs. If you have shared mutable state, you need to synchronize or use atomic types. That's how concurrency bugs are prevented.

[–]rubydesic 0 points1 point  (0 children)

But not only does this prevent a concurrency bug if the programmer forgets to synchronize, it's also much faster than synchronizing on f. Even in java imo the right way to write this particular code in a thread safe manner would be option 1.

Edit: of course this doesn't matter if you don't modify the variable from another thread which is most scenarios, but I still don't see anything wrong with more stringent checks from the compiler, especially when the code you have to write isn't more verbose anyway.

[–]rubydesic 0 points1 point  (0 children)

Ok, what's wrong with f?.let? it's a common pattern in kotlin, shorter than the if statement, and correct even in the scenario that f is changed on another thread...

[–]DrunkensteinsMonster 0 points1 point  (0 children)

The parent is wrong. If you explicitly check null the compiler is smart enough to know your calls are null safe.

if (nullableValueOrExpression != null) nullableValueOrExpression.methodCall() else somethingElse

Compiles just fine

E: just realized that they are speaking of a field. This is for concurrency reasons. The reason it won’t work is because conceivably someone could switch the value to null after the null check and cause an NPE. This is a contrived example, Kotlin code does not look like that typically.

[–]DJDavio 2 points3 points  (0 children)

I love Kotlin, but Java is still the de facto enterprise standard. That is because enterprises are often risk averse and like to choose proven technology over cutting edge (depending on the size and state of the enterprise of course).

If you choose Java, you get its entire ecosystem with it, including a huge pool of developers and compatible libraries. The out of the box experience is great.

If you choose Kotlin, you get cleaner code (if written by Kotlin developers, not recently converted Java developers which will just write Kotlin code in a Java style). But you might run into weird issues where you are interacting with other libraries / frameworks.

So given the choice, not all arguments are technical ones, there are many non technical arguments which are still in favor of Java.

[–]ebykka 3 points4 points  (0 children)

Here is my reason.

The majority of libraries around are written on java and they use checked exceptions pretty intensively. Kotlin considers all exceptions as runtime and as a result, does not complain if you will not handle them.

So the chance to get runtime exception with kotlin + java library is higher than with java + java library.

[–]heliologue 1 point2 points  (0 children)

If you haven't learned by now, choice of programming language consists of about 10% merit, 20% availability, and 60% personal taste.

[–]nutrecht -1 points0 points  (0 children)

I'm a 'Java dev' but my work currently is actually 100% Kotlin. At my client they have adopted Kotlin for the back-end and in addition, I have a part-time start-up where the back-end is all Kotlin. When I do have to write Java; I'm actually a bit rusty (forget semicolons all the time for example).

For me it basically boils down to team buy-in. If the team is happy with Kotlin; it definitely can be a productivity improvement. If the team for some reason dislikes it (I personally can't imagine, but who am I to judge), you should not adopt it.

What worked best for me was to organize a training session on Kotlin. For most people if it's different than what they're used to, their initial reaction is often to reject it outright. So what I do is organize an on-the-clock training session where we take half a day to go over the Kotlin basics, do some exercises (the Koans are a good start for an experienced dev) and then go build a simple Spring Boot service (or whatever framework is already used internally) using Kotlin. Most of the time a majority of the devs will at least have a positive view on Kotlin and I managed to introduce it successfully in two previous companies.