I never fully switched to Kotlin. It’s good, but not good enough. I also like the direction Java has been evolving in over the last 10 years, to the point that a JVM server is actually lighter than a Node.js server :)
Sure, Java is slowly getting most of the features and sometimes even in a better form because they control the runtime (virtual threads arguably just work). But IMO Java is still incredibly verbose, Kotlin's type system is just better and I've genuinely never come across anything that would be easier to do in Java. Even virtual threads can be used from Kotlin.
I see no reason other than Android, where Android engineers live in the past and don't bother to support modern Java, other than when Kotlin starts to lose the amount of Java libraries able to run on Android.
Many years ago I learnt that mastering the language that goes alongside the platform is quite valuable versus the languages that come and go.
Hence why despite my rants, I keep my C knowledge up to date, as it is the language of UNIX, same with JavaScript on the Web, Erlang on BEAM, and naturally Java on the JVM, even though Scala and Clojure are much cooler.
> see the pace of Java development pick up so much over the past few years.
I don't think that is a fair assessment. Java / JVM has been steadily progressing in the past 10 - 15 years. From languages to different part of JVM. It is only getting the sense development being picked up because HN and other social media are finally getting the clicks and interest again. The pendulum swing back because of all of different reasons.
And in reality a lot of these recent landed improvement were 5 - 10 years in the making.
I still don't like its syntax though. But I am not even sure if it is even an issue in AI driven development era.
> Yah but why? The things it was good at doesn’t really matter nearly as much post AI.
Pretty much the opposite. Those who disliked it usually cited having to type too much due to class verbosity and variable verbosity (the former has merit, the latter was purely a choice).
If you no longer need to type in any of the code, what better than a language with a blazing fast and scalable runtime, with excellent debugging and monitoring support.
Quite the opposite. Java is almost all about an optimising runtime with deep telemetry, and it helps with exactly the things AI needs the most help: https://youtu.be/fXBGBovpH88
Most people are thirsting for value objects but I'm mostly looking forward to:
542: PEM Encodings of Cryptographic Objects
543: Structured Concurrency
Developers work with certificates a bit too seldom to aquire proficiency with conversions. Being able to use PEM directly will ease a lot of pain.
I've given concurrency a couple of attempts over the years and I don't... like... or understand?... how the existing Java concurrency primitives are supposed to work. The only library that has clicked with me is Awaitility but for some reason Awaitility is intended for testing and not for production. Maybe Structured Concurrency will finally unlock something for me?
You can also choose to run directly from source with a small penalty at startup and verbosity has decreased for simple use cases. It's still not great for scripting but the situation has been steadily improving over the last couple of years.
void main() {
IO.println("Hello world");
}
$ time java Hello.java
Hello world
real 0m0.662s
user 0m2.421s
sys 0m0.198s
void main(String[] args) throws Exception {
IO.println(InetAddress.getByName(args[0]));
}
$ time java Dig.java news.ycombinator.com
news.ycombinator.com/209.216.230.207
real 0m1.154s
user 0m2.379s
sys 0m0.222s
Spring is slow because it scans the classpath, uses reflection and generates proxy classes all at startup. You can avoid some of that using the Spring AOT feature in newer versions.
Or you can just use a different framework like Micronaut which does none of that and uses an annotation processor at compile time instead. (Similar to Spring AOT, with fewer limitations)
Won't address start up time since it's so affected by which libraries you pull. Slow starts are usually related to dependency injection frameworks like Spring or Guice, which admittedly is what most nontrivial projects will tend to use.
Performance depends a lot on how you write the code. Inefficient Java code is often quite slow, but you can get surprisingly close to C++ speeds with Java in many cases, but that involves a lot of byzantine rules of how to write code so that it e.g. omits bounds checks. More realistically if you don't pay any attention you're probably running at like a 25-50% speed penalty.
Java has a leg up on statically compiled languages in that it does automatic PGO based on real run-time data which helps bridge the gap to a surprising degree. GC is also a lot more resistant to memory fragmentation from repeated small allocations than malloc, which can help as well, not just from its generational approach but also e.g. TLAB space.
It's a bit held back by not having decent access to SIMD intrinsics. Maybe will resolve itself when the Vector API gets finished baking eventually.
Sorry if it is trivial but bc you asked shell command and if meant the "java script.java" no compile way: even that is fast, but if you run in a shell script loop thousand times, then do not forget to compile.
We use it at scale in different systems. We are moving away from it in our serverless functions due to the cold start times. Other, less latency sensitive services are OK.
But does AOT really help performance wise? It helps with start time, but it probably performs worse after that because of lack of CPU specific optimizations (excluding JIT time).
JIT + hotspot optimization makes JVM pretty fast, but warmup time is usually the problem. However it does look like they’re addressing startup time with improvements in this release:
Other posters here seem to misunderstand what AOT means in today's Java. It just means caching some state. There's still a JIT involved, it's just warmer.
Very fast. And yes, it can be used for small apps too. With java problem now is not the performance but how verbose still it is. However, it's much better since Java 17 and each release make it even more compact and direct. Like in this release we got much better built-in support for JSON.
I couldn’t find it in the docs, but does the OpenJDK contain Java’s GUI? It would be cool to write the backend in whatever language you want and then have an ACTUAL library that works on all platforms that also looks like the system GUI
Swing with the Nimbus Look and Feel isn't too bad for a quick, functionality-focused widget and it's super handy to have it still built into the JDK. It's not a good option for building a long term desktop application UI now though. There is no on-going development, the focus is now in Java FX. Prior to AI tooling, finding answers to Swing questions was getting much harder. Surprisingly I've found Claude to be pretty good at providing simple Swing UIs.
This is the answer for native theming, but you do end up opting in for a more difficult build process to make it work (JNI libraries and generation). Most devs will choose AWT/Swing because it's a lot simpler.
Fortunately, we now have 50 years of evidence of the negative effects of this philosophy on the ecosystem. Being strict in both results in net positive effects for the entire ecosystem. Trying to be lenient in what you accept results in HTML5, where the exact parse tree for every possible input sequence is specified in order to enforce compatibility. It's no longer lenient, because that doesn't work.
One is „accept a wide array of syntactically malformed input, ill defined, substantially complicating the parser“, the other „accept two trivial extensions to the standard that are widely used and don’t affect the resulting data in any way.“
From the JEP's goals: "Provide only those data types and operations required for strict conformance to RFC 8259, in order to facilitate machine-to-machine communication."
In that case they made the right choice, as machines won't be inserting trailing commas or comments in the first place, and the risk of having consuming apps inadvertently accept invalid data would be high otherwise.
This is a great way to ensure you have good application interoperability, but really starts going down hill when you're talking about security and consistency.
From the perspective of the one and only app you care about it may improve operability of that app with others.
But from the perspective of a potentially distributed ecosystem of apps and libraries as employed in practice in modern systems, it's actually harmful to interoperability.
Other libs/services/apps that touch the malformed JSON that this change would accept might be present in the overall system and crash on that data. The risk grows with the more components of the overall system that silently accept malformed data and allow the bad data to make its way deeper before it causes issues.
This is what “fail fast” was meant for, if something is going to cause problems in your system at some point in the future, make that “some point” happen ASAP, so that it is easier to identify and fix the source of the flaw.
It's really refreshing to see the pace of Java development pick up so much over the past few years.
The last few years of server-side has been on Kotlin for me, however, modern Java is looking more and more like anything I'd need in a language.
I never fully switched to Kotlin. It’s good, but not good enough. I also like the direction Java has been evolving in over the last 10 years, to the point that a JVM server is actually lighter than a Node.js server :)
What wasn't "good enough" for you in Kotlin?
Sure, Java is slowly getting most of the features and sometimes even in a better form because they control the runtime (virtual threads arguably just work). But IMO Java is still incredibly verbose, Kotlin's type system is just better and I've genuinely never come across anything that would be easier to do in Java. Even virtual threads can be used from Kotlin.
3 replies →
I see no reason other than Android, where Android engineers live in the past and don't bother to support modern Java, other than when Kotlin starts to lose the amount of Java libraries able to run on Android.
Many years ago I learnt that mastering the language that goes alongside the platform is quite valuable versus the languages that come and go.
Hence why despite my rants, I keep my C knowledge up to date, as it is the language of UNIX, same with JavaScript on the Web, Erlang on BEAM, and naturally Java on the JVM, even though Scala and Clojure are much cooler.
Elixir developers outnumber Erlang 2 to 1, I think you'd do well with Elixir.
[dead]
I’m so glad they made that change. So much better than the old days.
I love Java and I’m so glad it’s kept improving so much despite all the turmoil in its ownership.
> see the pace of Java development pick up so much over the past few years.
I don't think that is a fair assessment. Java / JVM has been steadily progressing in the past 10 - 15 years. From languages to different part of JVM. It is only getting the sense development being picked up because HN and other social media are finally getting the clicks and interest again. The pendulum swing back because of all of different reasons.
And in reality a lot of these recent landed improvement were 5 - 10 years in the making.
I still don't like its syntax though. But I am not even sure if it is even an issue in AI driven development era.
Java 8 (early 2014) is where Java got interesting again. Lambdas and streams fundamentally changed the language. java.time was a very big deal too.
Yah but why? The things it was good at doesn’t really matter nearly as much post AI.
> Yah but why? The things it was good at doesn’t really matter nearly as much post AI.
Pretty much the opposite. Those who disliked it usually cited having to type too much due to class verbosity and variable verbosity (the former has merit, the latter was purely a choice).
If you no longer need to type in any of the code, what better than a language with a blazing fast and scalable runtime, with excellent debugging and monitoring support.
10 replies →
Quite the opposite. Java is almost all about an optimising runtime with deep telemetry, and it helps with exactly the things AI needs the most help: https://youtu.be/fXBGBovpH88
8 replies →
Most people are thirsting for value objects but I'm mostly looking forward to:
Developers work with certificates a bit too seldom to aquire proficiency with conversions. Being able to use PEM directly will ease a lot of pain.
I've given concurrency a couple of attempts over the years and I don't... like... or understand?... how the existing Java concurrency primitives are supposed to work. The only library that has clicked with me is Awaitility but for some reason Awaitility is intended for testing and not for production. Maybe Structured Concurrency will finally unlock something for me?
> Developers work with certificates a bit too seldom to aquire proficiency with conversions. Being able to use PEM directly will ease a lot of pain.
While I certainly welcome this in the JDK, in practice it hasn't been a huge issue since a lot of people just use Bouncycastle to get that support.
I'm curious what about Java concurrency hasn't made sense or not clicked? Also in comparison to other languages like Erlang or just in general?
The big deal with this release is value objects preview. https://openjdk.org/jeps/401
I always learn a ton from these release notes and go back and read the JEP…. So fascinating how all this stuff works.
I'm not a Java person, but I'm curious how fast it is nowadays, and also the startup time. Can it be used to write shell commands with, for example?
For some reason this machine is still on 21. Anyway, the overhead of the JVM itself is pretty low.
For small tools it's fine:
Java startup gets slow when you use some massive framework like Spring. If you need a program to start fast, don't use one!
You can also choose to run directly from source with a small penalty at startup and verbosity has decreased for simple use cases. It's still not great for scripting but the situation has been steadily improving over the last couple of years.
1 reply →
Spring is slow because it scans the classpath, uses reflection and generates proxy classes all at startup. You can avoid some of that using the Spring AOT feature in newer versions.
Or you can just use a different framework like Micronaut which does none of that and uses an annotation processor at compile time instead. (Similar to Spring AOT, with fewer limitations)
Won't address start up time since it's so affected by which libraries you pull. Slow starts are usually related to dependency injection frameworks like Spring or Guice, which admittedly is what most nontrivial projects will tend to use.
Performance depends a lot on how you write the code. Inefficient Java code is often quite slow, but you can get surprisingly close to C++ speeds with Java in many cases, but that involves a lot of byzantine rules of how to write code so that it e.g. omits bounds checks. More realistically if you don't pay any attention you're probably running at like a 25-50% speed penalty.
Java has a leg up on statically compiled languages in that it does automatic PGO based on real run-time data which helps bridge the gap to a surprising degree. GC is also a lot more resistant to memory fragmentation from repeated small allocations than malloc, which can help as well, not just from its generational approach but also e.g. TLAB space.
It's a bit held back by not having decent access to SIMD intrinsics. Maybe will resolve itself when the Vector API gets finished baking eventually.
There's ongoing work to improve JVM startup time. [1]
So long as you are willing to do a training run, you can get pretty decent startup times.
[1] https://openjdk.org/projects/leyden/
I'm using JDK 21 (old) and the startup time is sub-second for small programs.
That’s not the flex you seem to think
1 reply →
Sorry if it is trivial but bc you asked shell command and if meant the "java script.java" no compile way: even that is fast, but if you run in a shell script loop thousand times, then do not forget to compile.
We use it at scale in different systems. We are moving away from it in our serverless functions due to the cold start times. Other, less latency sensitive services are OK.
What sort of domain are you in? And what are you moving to?
1 reply →
For 20+ years already, most commercial JDKs have had AOT support, long before GraalVM and Open J9 became open source.
But does AOT really help performance wise? It helps with start time, but it probably performs worse after that because of lack of CPU specific optimizations (excluding JIT time).
3 replies →
Startup time depends on whether you are using Spring heavily or not. I wouldn’t use it as a shell script replacement. Use Python to that end.
JIT + hotspot optimization makes JVM pretty fast, but warmup time is usually the problem. However it does look like they’re addressing startup time with improvements in this release:
- AOT compilation: https://openjdk.org/jeps/544 - ~100ms startup for ZGC: https://openjdk.org/jeps/545
This is only an issue on OpenJDK, other JVM implementations have had AOT tooling for quite some time.
Every time I try, I keep going back to .NET, which has been optimising for faster startup time.
Almost all Java benchmarks are for the "steady state" after half an hour of warm up time.
Doesn't Java have an AOT solution too? Is it not ready for prime time?
3 replies →
Other posters here seem to misunderstand what AOT means in today's Java. It just means caching some state. There's still a JIT involved, it's just warmer.
There are other solutions that give you MUCH faster startup with lower memory e.g.: https://foojay.io/today/java-server-work-before-startup/
Edit: it seems I missed that 28 added the actual native code compilation phase so it will probably be closer to the GraalVM numbers in the link above.
1 reply →
Very fast. And yes, it can be used for small apps too. With java problem now is not the performance but how verbose still it is. However, it's much better since Java 17 and each release make it even more compact and direct. Like in this release we got much better built-in support for JSON.
I am looking forward these advances to reach IntelliJ/Eclipse and Netbeans.
Easy, change the default JVM.
I couldn’t find it in the docs, but does the OpenJDK contain Java’s GUI? It would be cool to write the backend in whatever language you want and then have an ACTUAL library that works on all platforms that also looks like the system GUI
It is bundled with Swing and AWT, but neither really looks like native, which has been a consistent complaint about them.
There is also JavaFX, but that is no longer bundled with the JDK.
Swing with the Nimbus Look and Feel isn't too bad for a quick, functionality-focused widget and it's super handy to have it still built into the JDK. It's not a good option for building a long term desktop application UI now though. There is no on-going development, the focus is now in Java FX. Prior to AI tooling, finding answers to Swing questions was getting much harder. Surprisingly I've found Claude to be pretty good at providing simple Swing UIs.
You can also make web frontends in Java for over a decade. This allows a full-stack app in Pure Java:
* React replacement: Flavour ( https://frequal.com/Flavour/book.html )
* Vanilla JS equivalent: TeaVM ( https://www.teavm.org/ )
Eclipse SWT ?
This is the answer for native theming, but you do end up opting in for a more difficult build process to make it work (JNI libraries and generation). Most devs will choose AWT/Swing because it's a lot simpler.
JEP 540: Simple JSON API
Be strict in what you produce, be lenient in what you accept. Grr.
Fortunately, we now have 50 years of evidence of the negative effects of this philosophy on the ecosystem. Being strict in both results in net positive effects for the entire ecosystem. Trying to be lenient in what you accept results in HTML5, where the exact parse tree for every possible input sequence is specified in order to enforce compatibility. It's no longer lenient, because that doesn't work.
Apples and oranges.
One is „accept a wide array of syntactically malformed input, ill defined, substantially complicating the parser“, the other „accept two trivial extensions to the standard that are widely used and don’t affect the resulting data in any way.“
2 replies →
From the JEP's goals: "Provide only those data types and operations required for strict conformance to RFC 8259, in order to facilitate machine-to-machine communication."
In that case they made the right choice, as machines won't be inserting trailing commas or comments in the first place, and the risk of having consuming apps inadvertently accept invalid data would be high otherwise.
This is a great way to ensure you have good application interoperability, but really starts going down hill when you're talking about security and consistency.
From the perspective of the one and only app you care about it may improve operability of that app with others.
But from the perspective of a potentially distributed ecosystem of apps and libraries as employed in practice in modern systems, it's actually harmful to interoperability.
Other libs/services/apps that touch the malformed JSON that this change would accept might be present in the overall system and crash on that data. The risk grows with the more components of the overall system that silently accept malformed data and allow the bad data to make its way deeper before it causes issues.
This is what “fail fast” was meant for, if something is going to cause problems in your system at some point in the future, make that “some point” happen ASAP, so that it is easier to identify and fix the source of the flaw.
that was good advice back then. It is not good advice in 2026