Hacker News new | past | comments | ask | show | jobs | submit login

> * data class Foo(val theImplementationAndStyleOfDataClasses: String)

For the purists there are records now in Java (which can be combined with destructuring / pattern matching - there were significant improvements in this area in the last few JDK releases, and more are coming!). In this regard Java had surpassed Kotlin by some margin.

For the enterprise coders, there is the Immutables project (https://immutables.org) which you can say is Lombok on steroids (but implemented correctly, that is, by generating classes which you can inspect as regular source code, instead of relying on hacking the compiler...).

> * elvis?.operator?.chaining

This will hopefully be finally resolved by one of the subprojects of project Valhalla, as a prerequisite for value class support (which cannot be null, so...).

The others on your list are small and subjective stylistic differences, of course your preference may vary, but should not weigh heavily in any Java vs Kotlin discussion.




Java records do not have a copy method (or with clause or whatever equivalent), and there are no keyword arguments.

This makes Java records extremely painful to use for any data has more than 3 fields or so. You could use them together with an annotation processor like RecordBuilder (or Immutables or Lombok, but I don't think they support records?), but that's just not pure Java. Annotation processors that generate byte code always come with their own complexity.

Kotlin data classes have their own warts (order-based destructuring can be dangerous and the copy() method is a bit hacky) but the overall ergonomics for large value objects are better than Java records at this point.


Lombok supports `@With` on records, which adds wither methods. And there are ongoing JEP discussions on how to support this natively in Java.

Lombok is so ubiquitous today that I effectively consider it part of the language. And even with Lombok, the Java toolchain is so much faster, easier to use, and more stable than Kotlin.

Kotlin is a great language, marginally better than Java, but I'm not sure it's worth enduring the toolchain. And Java keeps improving.


If you think Kotlin is marginally better than Java, you probably have a superficial understanding of Kotlin. Kotlin is vastly better than Java, which isn't surprising because Kotlin was designed 15 years later with the explicit goal of being a better Java and fixing as many of Java's design mistakes as possible. For example, the designers of Kotlin went through the book "Effective Java" and tried to avoid the listed pitfalls by design.

Java will never get close to Kotlin because even though Java can, and thankfully does, still improve, it's too late to revise many of it design decisions, and large language features often need to be considered in a language's design from the start.

On Android, Kotlin is an even bigger win because Android uses an old Java version and has become Kotlin-first.

In my opinion, Java will remain the best choice for libraries that target multiple JVM languages. For everything else, I use Kotlin without thinking twice. Kotlin 2.0 laid the groundwork for toolchain improvements, which have indeed been a long-standing pain point.


Nah: If you think Kotlin is vastly better than Java, then you have a poor grasp of Java. I offer the same evidence you did.

Having worked professionally in both, I find that good programmers can write excellent code in both languages; bad programmers can write terrible code in both languages. The average cultural practice of the Kotlin community is perhaps better than the average cultural practices of the Java community (which huge and defies averaging anyway). But Java code which emphasizes immutability, uses Optional instead of nulls, uses streams, etc is pretty indistinguishable from Kotlin.


I first learned Java in 1997 and have been using it professionally since 2005. If your Kotlin code is pretty indistinguishable from your Java code, you aren't using Kotlin properly. Here is what I wrote on this topic in 2022:

Here are some of my favorite Kotlin improvements over Java that I leverage all the time:

* Much improved type system (nullable types, function types, declaration site variance, type aliases, contracts, better type inference, reified function type arguments)

* Local variables are final by default ("val")

* Type-level distinction between read-only and mutable collections (but compiled to Java collections under the hood, so no conversion required when interacting with Java)

* Much improved collection API

* Much improved lambdas (e.g., no pain points w/ mutating variables and checked exceptions)

* Extension functions (incredibly useful in practice)

* Much better DSL capabilities (great for UIs, generating HTML, etc.)

* Lazy properties (more generally: delegated properties)

* Coroutines (looking forward to Java's Loom; by then coroutines will have dramatically improved my async code for 5+ years)

* Great serialization support (kotlinx.serialization)

* Pragmatic macro-like capabilities via inline functions and compiler plugins (removes lots of boilerplate)

* Multiplatform support (JVM/JS/WASM/native; Graal native image is a good alternative to Kotlin/native and also works for Java)


I'll go through a few of these, but not all:

* Yes, the Kotlin type system is better, no question. And yet it doesn't really matter for 90% of code, Java's type system is "good enough". And in the places where it tends to suffer, IntelliJ ends up covering the ground anyway (validating various annotation values, spring properties, sql, etc).

* The difference between nullable types and Optional<?> types is not material. TBH I quite like Optional<?> and how it meshes with streams.

* "final by default" is indeed nice. But putting `final` everywhere (which we do) is at most a tiny annoyance. This is not material.

* Clear type distinctions between mutable and readonly collections is better, but not material, because we treat all collections as immutable.

* Java streams hit 90% good enough, and StreamEx tends to fill in another 9%.

* We don't have pain points with mutating variables in closures because we don't use mutable variables.

* We don't have problems with checked exceptions because we don't use checked exceptions (and when interfacing with foreign code that throws checked exceptions, we use @SneakyThrows or wrap).

* Coroutines are a major net negative for Kotlin, and Loom is already here. After many years of async programming in JS/TS, Ruby, and (going back far enough) C++, I've concluded that async programming (and function coloring) is absolutely toxic and should be avoided unless it's absolutely required for performance (or the platform, ie GUIs).

* Multiplatform support has great future potential, but it doesn't seem to be ready yet. I just started a greenfield project and _really_ wanted to use KMP. Decided against it in favor of a React frontend. I don't want to live on the bleeding edge, I have work to do. And I've been bitten by deadended technologies enough times in my life to know the risk isn't worth it.

I could go on but I think you get the point - my Java looks like Kotlin, and the parts of Kotlin that would really diverge from my code aren't things I want. You could tell me that I should use coroutines everywhere and I just simply disagree.


> This will hopefully be finally resolved by one of the subprojects of project Valhalla

I think we'll see them come in through https://openjdk.org/jeps/8303099 although I'm not a huge fan of the approach chosen (tri state nullability: explicitly nullable, explicitly non-nullable, legacy code that should just be treated as nullable).

Except for native support for reification, almost all of Kotlin can be reimplemented by Java if you wait long enough and stack enough class annotations. It's all stylistic up to a certain point, but the classic Java style combined with the glacial improvement process is one reason why some people want to use a different language.

I think I'll have an easier time convincing someone to consider Kotlin than I'll have convincing someone to add Immutables+Manifold to the dependency chain. You end up writing Java that's not really Java like, but also not something that there's a good standard style for, and that usually ends up in a mess.

I'm glad with pattern matching, Java is now pushing Kotlin to improve rather than the other way around. I'll hope to use those features one day, when companies finally upgrade from Java 11 to Java 17 in five or ten years.


> pattern matching ... In this regard Java had surpassed Kotlin by some margin.

I did just glance at Java's pattern matching; and yeah, it does look like it is a bit more powerful than Kotlin's pattern matching in that it can, at the same time, look for both type and a conditional. That's relatively neat - not something I've personally needed / wanted; but neat just the same :)

The JVM is a really nice virtual machine in how it lets us use both of these languages fully interchangeably to pick the one we like more.

I'm glad Java has been investing in some of these areas, too. Everyone improves when paradigms and new learnings are distilled.


Kotlin 2.1 has added "Guard conditions in when with a subject" as an opt-in feature https://kotlinlang.org/docs/whatsnew21.html#guard-conditions...




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: