Modern Java
48 points by chris-evelyn
48 points by chris-evelyn
Didn't see any mention of sealed interfaces, which are IMO one of the least appreciated improvements to the language. They are essentially union types for Java and you can implement them on records as of 17. And as of 21 you now have exhaustive switch statements that work with them. It completely changes the programming model from inheritance and dynamic dispatch to ADTs.
It took them a while but I respect how slow it they evolve the language; it's my favorite among the mainstream ones for that reason. They didn't jump on the async/await bandwagon many years ago and now they have a much more general solution with virtual threads and aren't saddled by coloring / API duplication that C# has to deal with. It's become a pretty great language.
Randomly stumbled upon this little book. It accomplished two things:
Java was already kinda good 10 years ago, the problem is its low quality ecosystem. Even fundamental stuff like JSON parsing was riddled with absurd bugs in extremely widely used libraries, not to speak of all the overcomplicated enterprise libraries.
If you ignore the ecosystem, or restrict yourself to a small set of "known good" libraries, then Java is actually quite pleasant!
Off-topic: I think that Rust is heading in the same direction, ecosystem-wise. Thousands of libraries, all mediocre and bloated.
Interestingly enough I think the prevailing sentiment is the other way around -- Java-the-language as being archaic, verbose, unusable, and so on, but Java-the-ecosystem (both the runtime and the wealth of libraries and support available) being just about best-in-class, which is why we've seen so many languages (Kotlin, Scala, Clojure, and the myriad others hosted on the JVM) whose value propositions are more or less "language that is usable and modern AND able to take full advantage of the power of the Java ecosystem"
I think the ecosystem bit was truer back then when high quality libraries didn't exist for some languages.
In my experience Java is still best-in-class for some things usually enterprise-related that no one in Open Source is really eager to solve. I've worked with the Java ecosystem for things like parsing PDFs correctly: at my previous job we dealt with the most varied types of PDFs and had to transform them. Most languages have good implementations that'll deal with 80% of the PDFs out there but break for the last 20%. This was a paid library too.
What else is Java best-in-class at? The pivot to cloud-ready software made other languages much more attractive, I haven't seen anyone choosing Java from the get go.
Java is better but I still prefer Kotlin or Scala. Many of my coworkers feel the same.
I predicted that Kotlin would eventually suffer the same fate as coffeescript -- gradually becoming less used as its host language catches up. Java has the built-in advantage of being able to evolve the bytecode format to suit its new features, like it did with records, whereas third-party JVM languages can't do that. And it can get especially awkward if the host language's version of the feature doesn't quite match with the hosted language's. The hosted languages that don't suffer this fate are the ones that dramatically part ways with the host, as Clojure does -- which is why Brian Goetz said it was his favorite non-Java language on the JVM.
It's something I think about it too. But right now I still prefer Kotlin. Sometimes Java has added the same features as Kotlin but they're not as nice, for example the whole streams and lambda stuff is much nicer in Kotlin. Java has Virtual Threads now but if you want to program in a async/await fashion Kotlin coroutines are still very ergonomic and you can also use Virtual Threads from Kotlin if you want the other concurrency style. A big thing missing is the whole nullability control in the type system. Optional is a joke, it's not the same as Kotlin ? types. But this is a difficult issue for Java as it can introduce non-backward compatible changes. I've heard that they're working on it but the end result may not be as clean as the way Kotlin has it. Scala, which I'm using right now, has other things that deviate from Java because Scala is more than just "a better Java", at least for some people. But it suffers from a split ecosystem, lack of new people entering the ecosystem, a difficult transition Scala 2 -> 3. Which is a shame because things like Scala Native could be the "easier Rust" that some people are looking for.
As someone who codes in Kotlin on the daily but also writes Java occasionally, I'm delighted to see Java closing the gap. It's good for the JVM ecosystem, and the industry as a whole, if Java gets better and better over time.
But while Kotlin isn't nearly as far removed from Java as Clojure is, I think there are still some differences that reflect language design philosophy more than checking language features off a checklist, and they'll make people less eager to jump ship.
The biggest one, to me, is that lambda functions are deeply baked into the entire language's design from top to bottom, supported by concise syntax, first-class status in the type system, and the standard library. Java has lambda functions, of course, but they're more awkward and verbose both to declare and to use, and when I write Java, I find myself reaching for them less often because they sometimes don't feel like the idiomatic way to solve a problem.
On some level you could say it's syntax sugar, but the sugar really matters: Kotlin's type-safe builder pattern makes it possible to build little DSLs to express complex data structures concisely with full type safety. I've used it to build DSLs for defining unit test scenarios for my application's business logic, and the syntax is concise and clutter-free enough that domain experts who don't know Kotlin are able to review my test code to make sure the scenarios are correct.
That said, if Java continues to improve and Kotlin eventually withers away, I'll be fine with switching back to Java; I never hated it in the first place and it's perfectly fine.
Gave me a "What, Java is kinda good now?" moment
I have a silly anecdo-theory that any old language with explicit versioning will suffer a similar fate. Java is full of cool stuff now, but there's still so much baggage from Java 8 and the even older days, that it overshadows the many improvements.
Even without TS covering up the warts, modern JS, with "use strict", avoiding ==, properly using the class system and utilizing the newer parts of the standard lib is a far less foot-gun of a language than it's famous for. Yet the language is still often judged for its pre-ES6 quirks and crappiness.
Similarly with C++. Modern C++ can look almost as high-level as a proper functional language, with some seriously impressive batteries, but because of decades of "C with classes", even stuff like smart pointers isn't always the obvious choice to newcomers.
Hell, even C arguably has this with its K&R style, which has some pretty bonkers restrictions compared to ANSI and above.
I think for JS part of it is that the shiny new APIs are often second-class. You can't use bracket syntax with maps, you have to use method calls. Plain JS objects serialize/deserialize easily using JSON, but maps don't. And if you have some data structure with a bunch of nested classes, deserializing it is a pain.
I think interpreted languages like JS also get it worse because you have to worry about what's available on your user's machine. With Rust or C++, I can use whatever fancy new string methods or decorators or whatever without having to think about the runtime environment.