- context receivers (think of them as implicit parameters that are checked at compile-time)
- null safety. This is a BIG one, especially if you’re coming from Java.
- structured concurrency. Java still doesn’t have this. Note that SC is different from what was introduced in Project Loom.
- immutable variables, data classes, value classes etc.
The area Kotlin excels in isn't as a pure Java replacement to be used by Java devs but rather a JVM language palatable to the Python/Javascript/Ruby/Golang crowd. It's very very hard to convince such people that they should even try Java but Kotlin is much easier to at least get them to try and show them it's really not hard at all.
One of the most egregious destructions of great value in the modern world wasn't the collapse of the Key Bridge or the destruction of the library of Alexandria -- it was when Jython, a wonderful implementation of Python2 on the JVM, died because it was too much effort to upgrade it to support Python3. So much value and capital, destroyed because of the damn 2to3 fiasco. ALL FOR WHAT? For goddamned PRINT STATEMENTS?
Now all the libraries have moved on, so Jython is not so useful -- you can do toystuff but you can't import any serious modern python library anymore, which you could a decade ago! And you got real multithreading with no GIL to worry about it! It was ahead of the real CPython2!
It was more than just a way to integrate and glue together Java and Python code -- it was actually a viable alternative Python runtime. It's a big reason I've never forgiven or started retrusting the python community after the 2to3 fiasco. It just shows it's not a serious language like java that actually cares about backwards compatibility and is able to advance anyway.
Hey, what ever happened to Groovy? It was like Scala/Kotlin but without taking itself seriously at all, much more akin to perl than to C++.
I also prefer a smaller languages - and I feel earlier versions of Kotlin were beautifully balanced in this regard with a small(ish) number of powerful and orthogonal improvements over Java. The language has grown significantly since then at a far faster rate than Java - maybe approaching C# velocity.
Finally, and I realise that a lot of effort has gone into addressing the issue in recent releases but compile times were much worse for me than equivalent Java.
Now that java itself is adding many functionalities inspired from other languages, it's much less appealing.
I saw some backend projects at $company, and after 2 or 3 years, the decision was made to only use java on new files, and convert kotlin files to java when they are touched. Why? The kotlin compiler was so much slower that it was noticeable, while javac is still very fast. Another reason is available talent not related to Android. Lastly, its value proposition wasn't high enough to justify a different language, especially with java 17 and later.
That being said, even quarkus provides kotlin apis nowadays, so it's not like it doesn't happen.
There are other reports to dive into.
Java hasn't taken that much from Kotlin really, sometimes even gone in a completely opposite direction (for instance with Loom).
Java has taken a few things from Scala but I would hardly call them the best features. Java will never adopt what truly makes Scala stand out, on purpose.
In the meantime, Java took a lot of the good features and made them even better, e.g. Java has actual pattern matching and Kotlin doesn't.
Google provides first-class support for Kotlin. Oracle does not. Kotlin does not evolve with JVM. For example they introduced coroutines to imitate blocking code and few years later Java decided to create green threads, making the feature essentially obsolete.
Kotlin made sense in Java 1.7 time, when Java seemed to be stale and kind of dead. Things changed since then.