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.
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:
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.
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)
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.
We develop back-end infra related to data streaming (think Kafka). Our main processing engines are written in Java. The control plane uses Lambdas, we are moving those to rust now.
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).
Why are SLAs the bar for performance? Every additional second of execution time accumulates in the annual cloud bill, and using too much memory means I need a bigger box.
For example, the C++ replacement for a Java program bottlenecking my CI takes 1/3rd as long (with less variance) and runs on a smaller instance.
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.
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.
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.“
So far nobody has tried to get trailing commas into the standard AFAIK.
Comments were explicitly disallowed from JSON since the beginning, because they could be used as a side-channel for vendor-specific extension mechanisms and harm interoperability.
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.
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
I now manage a team writing languages on the jvm. I have found the jvm ecosystem terrible for observability. Examples;
- junit parallelisation - how are shards handled? how do you balance the tasks across forked processes? What is the bottleneck? Options are
1) pay someone for better tooling or 2) write your own
- long pauses in garbage collection - how do you know which objects are causing the pauses? the options;
1) profiling 2) analysing heap dumps that you periodically capture 3) add metrics or gc logging
- what is the performance bottleneck? options
1) profiling
Sure AI can do this stuff, but it's painful and time consuming
Contrast it to Elixir on the BEAM;
- exunit parallelization - basically free and because you don't have coupling due to OOP. mocks are basically an antipattern
- long pauses due to gc? They just don't happen - everything is isolated and can be cleaned up in parallel.
- performance bottleneck? Open inspector and see what is doing all the reductions, and if any of the inbox queues are backlogged. You don't have to profile, you can just look in production
- memory? Open inspector and sort processes by size descending. Again no profiling needed
JFR is what you'd use for everything you need to know. It's depth and breadth are unmatched.
> Contrast it to Elixir on the BEAM;
Java is in the same performance class as C++. BEAM is wonderful in its own way, but it's not even in the same performance class as Go.
BEAM was designed for some interesting resilience in distributed systems. The JVM was designed to address the performance issues that programs in C++ and other low-level languages suffer from when they get large and/or are maintained/evolved for a long time.
> long pauses due to gc? They just don't happen - everything is isolated and can be cleaned up in parallel.
GC pauses in the JVM have been optional for a few years now. ZGC doesn't have GC pauses.
We're talking past each other a bit. I was just trying to give examples of where observability on the jvm isn't that great, because you were were stating it's where AI needs the most help.
The parent was saying these new features don't matter as much post-AI and i think I agree with them. The AI can just write in rust if you need to optimise a hot loop, but if you need observability, you could do worse than the BEAM.
> GC pauses in the JVM have been optional for a few years now. ZGC doesn't have GC pauses.
yeah that's a fair comment, zgc is a lot better for pauses. I'd still say that it pulls along a fair bit of incidental complexity - it encourages you to allocate a fair amount of memory to your heap, which isn't ideal in this world of kubernetes and microservices. If you leave on uncommit (returning memory to he OS periodically) you get extra latency penalties which are just as painful as garbage collection stalls IMHO.
BEAM's observability is very good, but JFR is unmatched. We're not talking about debugging, but about low-overhead deep telemetry (or "always on, in-production profiling"). eBPF helps, but it doesn't come close (e.g. dynamic allocations are much expensive in low-level languages than in Java, but even if you probe malloc, it doesn't tell you the type of the object allocated).
> The AI can just write in rust if you need to optimise a hot loop
Why would it when it could just write it in Java? The JVM was invented not because we couldn't write code in C++ but, among other things, to optimise things (especially around memory management and inlining) that low-level languages have trouble optimising in a large class of applications. If you're after the best performance, then you'll ask AI to use a low-level language when a low-level language offers better performance, and to use Java for applications when Java offers better performance.
Java isn't a performance compromise. It offers different tradeoffs that could make some programs significantly slower than low-level languages in some cases and significantly faster than low-level languages in others. That's the point of the approach taken by the JVM: to offer optimisation opportunities that aren't available in low-level languages. People who think low-level languages always offer better performance are people who have not had much experience with low-level languages. I originally came to Java from C++ because Java has optimisation opportunities that low-level languages don't (they have to compromise on performance in some situations for the sake of low-level control) that matter in certain but very common kinds of programs.
> zgc is a lot better for pauses
It has no real GC pauses. It does have minuscule pauses for synchronisations, but those are an optimisation, and they're no worse than OS jitter. In other words, if ZGC's pauses are a problem for you, then you won't use a non-realtime kernel, as you'll get similar pauses even in a C program on the same OS.
> I'd still say that it pulls along a fair bit of incidental complexity - it encourages you to allocate a fair amount of memory to your heap, which isn't ideal in this world of kubernetes and microservices.
It really doesn't. All of our GCs are optimised for a natural rate of allocation. They do discourage pooling objects to artificially reduce allocation rates, though, but it's easier to not pool than to pool.
> If you leave on uncommit (returning memory to he OS periodically) you get extra latency penalties which are just as painful as garbage collection stalls IMHO.
You get such stalls and worse with C++ or any other low-level language.
ZGC is effectively pause-free. It uses a STW pause for thread synchronisation of the epoch as an optimisation (we tried synchronising without the pause, but OS scheduling just slowed us down; maybe we'll use new OS techniques for synchronisation in the future). ZGC does zero GC work in these pauses. There is also no strong reason to remove the synchronisation pause because it is no longer than OS jitter (i.e. C programs can experience pauses of similar duration on non-realtime kernels).
BTW, SGCL is a non-moving mark-and-sweep collector and non-moving collectors are no more similar to moving collectors than malloc/free is similar to moving collectors. Garbage collection contains different classes of algorithms with different goals that are so different from one another that it's almost pointless to put them in the same category. Java uses moving collectors because it's the class of algorithms designed to reduce the throughput overhead of all non-moving approaches (from manual malloc/free, through automatic RAII and refcounting GC, through tracing mark-and-sweep collectors like SGCL or Go's GC). In important ways, all non-moving approaches are more similar to each other (regardless of the use of a GC) than any of them are to moving approaches. (Java did have a concurrent mark-and-sweep collector at one time, but we removed it some years ago)
> 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.
But if you want "blazing fast" performance then there are other languages like Rust that the AI can write, and Rust runs basically everywhere Java does these days (and more) except perhaps Android, for which there are still ways around it.
Primarily embedded, for which Java is basically unsupported for many use cases. Rust does have diagnostics and monitoring but it's debatable if they're as good as the JVM although again some places Java can't even run.
Incidentally, Java seems faster on the server side than Rust in several benchmarks I've seen and tried locally - yes to be taken with a grain of salt, but point being that Rust is not the be-all performance aspiration - there are some really good Java One 26 and Devoxx 26 talks pertaining to the importance of well spec'd languages like Java and runtimes like the JVM in the age of AI. And this is without talking about things like monitoring and observability.
For complex enough and long-running application your run-of-the-mill Rust (so probably what AI would generate) will likely be slower than your run-of-the-mill Java.
I know this is a heresy in some online religious groups pretending to care about engineering but that's reality.
> For complex enough and long-running application your run-of-the-mill Rust (so probably what AI would generate) will likely be slower than your run-of-the-mill Java.
That phrase "complex enough" seems to be quite load bearing.
At which point does complexity reach the tipping point where a Java implementation becomes faster? From my experience, the more complex the application, the more enerprisey the Java code becomes, relying heavily on dynamic capabilities that make it slow even by Java standards.
Many of us know how to write blazing fast code with Java, first step is embrace the ecosystem, followed by actually understanding algorithms and data structures.
Most rewrite language X in Y are justifications after the fact, when the real reason is language Y was cool for whatever reason.
Most importantly IMO the JVM ecosystem has lots of solid, battle-tested, enterprise-grade frameworks like Spring and Quarkus, which do all the heavy lifting for those kinds of applications. The code can still be verbose, but that is solved by LLMs, as you said.
Rust has all the individual bits you need as libraries (web server, database access, etc.) but you have to wire it all together yourself. Sure LLMs can do that too, but how do you know the LLM did it correctly? There could be complex interactions between the individual libraries.
Using a complete framework solves that, you know its bits will work together correctly. It also makes the code structure of different applications look more similar, which probably helps LLMs understand it better too.
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.
For me, Java 8 was tolerable. Also used IJ a lot and it hides Java verbosity and reduced a lot of typing. That's why I didn't really see the need to switch. For better or worse, these days I don't even open IJ and just use VSCode + AI Badger mostly to review my changes. Language matters even less.
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.
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.
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?
amelius | 22 hours ago
jiggawatts | 22 hours ago
Almost all Java benchmarks are for the "steady state" after half an hour of warm up time.
kg | 22 hours ago
miroljub | 22 hours ago
samus | 16 hours ago
pjmlp | 15 hours ago
invalidname | 20 hours ago
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.
pjmlp | 15 hours ago
OpenJDK, OpenJ9, Azul, PTC, Aicas, microEJ, ART (even if not Java TM), GraalVM, Bluesoft,..
ww520 | 22 hours ago
Havoc | 22 hours ago
ww520 | 22 hours ago
__natty__ | 22 hours ago
binary132 | 22 hours ago
- AOT compilation: https://openjdk.org/jeps/544 - ~100ms startup for ZGC: https://openjdk.org/jeps/545
pjmlp | 7 hours ago
azatom | 22 hours ago
illusive4080 | 20 hours ago
twic | 20 hours ago
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!tofflos | 12 hours ago
elFarto | an hour ago
kodebach | 10 hours ago
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)
OrangeDelonge | 19 hours ago
za3faran | 16 hours ago
OrangeDelonge | 7 hours ago
pjmlp | 15 hours ago
mihular | 15 hours ago
pjmlp | 14 hours ago
Also performance for what?
As long production SLA are met, that's a deployment success.
AlotOfReading | 7 minutes ago
For example, the C++ replacement for a Java program bottlenecking my CI takes 1/3rd as long (with less variance) and runs on a smaller instance.
marginalia_nu | 11 hours ago
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.
cogman10 | 9 minutes ago
So long as you are willing to do a training run, you can get pretty decent startup times.
[1] https://openjdk.org/projects/leyden/
MrBuddyCasino | 22 hours ago
mpyne | 21 hours ago
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.
chowells | 21 hours ago
MrBuddyCasino | 21 hours ago
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.“
dwohnitmok | 20 hours ago
That's always how it starts. If they're truly trivial the reasoning also cuts the other way. Remove them upstream.
dwaite | 19 hours ago
Comments were explicitly disallowed from JSON since the beginning, because they could be used as a side-channel for vendor-specific extension mechanisms and harm interoperability.
pixl97 | 21 hours ago
mpyne | 6 hours ago
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.
vrighter | 14 hours ago
jmarlow47 | 22 hours ago
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.
brianwawok | 21 hours ago
pron | 21 hours ago
anko | 20 hours ago
- junit parallelisation - how are shards handled? how do you balance the tasks across forked processes? What is the bottleneck? Options are 1) pay someone for better tooling or 2) write your own
- long pauses in garbage collection - how do you know which objects are causing the pauses? the options; 1) profiling 2) analysing heap dumps that you periodically capture 3) add metrics or gc logging
- what is the performance bottleneck? options 1) profiling
Sure AI can do this stuff, but it's painful and time consuming
Contrast it to Elixir on the BEAM;
- exunit parallelization - basically free and because you don't have coupling due to OOP. mocks are basically an antipattern
- long pauses due to gc? They just don't happen - everything is isolated and can be cleaned up in parallel.
- performance bottleneck? Open inspector and see what is doing all the reductions, and if any of the inbox queues are backlogged. You don't have to profile, you can just look in production - memory? Open inspector and sort processes by size descending. Again no profiling needed
pron | 18 hours ago
> Contrast it to Elixir on the BEAM;
Java is in the same performance class as C++. BEAM is wonderful in its own way, but it's not even in the same performance class as Go.
BEAM was designed for some interesting resilience in distributed systems. The JVM was designed to address the performance issues that programs in C++ and other low-level languages suffer from when they get large and/or are maintained/evolved for a long time.
> long pauses due to gc? They just don't happen - everything is isolated and can be cleaned up in parallel.
GC pauses in the JVM have been optional for a few years now. ZGC doesn't have GC pauses.
anko | 18 hours ago
The parent was saying these new features don't matter as much post-AI and i think I agree with them. The AI can just write in rust if you need to optimise a hot loop, but if you need observability, you could do worse than the BEAM.
> GC pauses in the JVM have been optional for a few years now. ZGC doesn't have GC pauses.
yeah that's a fair comment, zgc is a lot better for pauses. I'd still say that it pulls along a fair bit of incidental complexity - it encourages you to allocate a fair amount of memory to your heap, which isn't ideal in this world of kubernetes and microservices. If you leave on uncommit (returning memory to he OS periodically) you get extra latency penalties which are just as painful as garbage collection stalls IMHO.
pron | 5 hours ago
> The AI can just write in rust if you need to optimise a hot loop
Why would it when it could just write it in Java? The JVM was invented not because we couldn't write code in C++ but, among other things, to optimise things (especially around memory management and inlining) that low-level languages have trouble optimising in a large class of applications. If you're after the best performance, then you'll ask AI to use a low-level language when a low-level language offers better performance, and to use Java for applications when Java offers better performance.
Java isn't a performance compromise. It offers different tradeoffs that could make some programs significantly slower than low-level languages in some cases and significantly faster than low-level languages in others. That's the point of the approach taken by the JVM: to offer optimisation opportunities that aren't available in low-level languages. People who think low-level languages always offer better performance are people who have not had much experience with low-level languages. I originally came to Java from C++ because Java has optimisation opportunities that low-level languages don't (they have to compromise on performance in some situations for the sake of low-level control) that matter in certain but very common kinds of programs.
> zgc is a lot better for pauses
It has no real GC pauses. It does have minuscule pauses for synchronisations, but those are an optimisation, and they're no worse than OS jitter. In other words, if ZGC's pauses are a problem for you, then you won't use a non-realtime kernel, as you'll get similar pauses even in a C program on the same OS.
> I'd still say that it pulls along a fair bit of incidental complexity - it encourages you to allocate a fair amount of memory to your heap, which isn't ideal in this world of kubernetes and microservices.
It really doesn't. All of our GCs are optimised for a natural rate of allocation. They do discourage pooling objects to artificially reduce allocation rates, though, but it's easier to not pool than to pool.
> If you leave on uncommit (returning memory to he OS periodically) you get extra latency penalties which are just as painful as garbage collection stalls IMHO.
You get such stalls and worse with C++ or any other low-level language.
pebal | 2 hours ago
pron | an hour ago
BTW, SGCL is a non-moving mark-and-sweep collector and non-moving collectors are no more similar to moving collectors than malloc/free is similar to moving collectors. Garbage collection contains different classes of algorithms with different goals that are so different from one another that it's almost pointless to put them in the same category. Java uses moving collectors because it's the class of algorithms designed to reduce the throughput overhead of all non-moving approaches (from manual malloc/free, through automatic RAII and refcounting GC, through tracing mark-and-sweep collectors like SGCL or Go's GC). In important ways, all non-moving approaches are more similar to each other (regardless of the use of a GC) than any of them are to moving approaches. (Java did have a concurrent mark-and-sweep collector at one time, but we removed it some years ago)
jjav | 21 hours ago
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.
satvikpendem | 19 hours ago
jjav | 17 hours ago
I don't follow Rust as much as I wish I could if I had more free time.
What platforms are supported in Rust that don't support Java?
Does Rust have diagnostics, monitoring and debugging support anywhere near JVM quality?
satvikpendem | 13 hours ago
pjmlp | 7 hours ago
PTC, Aicas, microEJ, Ricoh, Xerox, Cisco, and several M2M vendors.
The first three even have bare metal variants, where the runtime is the OS.
Naturally they aren't targeting ESP32, Arduino, PIC class of devices.
za3faran | 16 hours ago
wolvesechoes | 14 hours ago
I know this is a heresy in some online religious groups pretending to care about engineering but that's reality.
bheadmaster | 14 hours ago
That phrase "complex enough" seems to be quite load bearing.
At which point does complexity reach the tipping point where a Java implementation becomes faster? From my experience, the more complex the application, the more enerprisey the Java code becomes, relying heavily on dynamic capabilities that make it slow even by Java standards.
pjmlp | 8 hours ago
Most rewrite language X in Y are justifications after the fact, when the real reason is language Y was cool for whatever reason.
kodebach | 10 hours ago
Rust has all the individual bits you need as libraries (web server, database access, etc.) but you have to wire it all together yourself. Sure LLMs can do that too, but how do you know the LLM did it correctly? There could be complex interactions between the individual libraries.
Using a complete framework solves that, you know its bits will work together correctly. It also makes the code structure of different applications look more similar, which probably helps LLMs understand it better too.
pjmlp | 8 hours ago
Thus anyone without issues using a GC language, regardless of which GC shape, has already plenty of choice on the JVM, not only the frameworks.
MBCook | 21 hours ago
I love Java and I’m so glad it’s kept improving so much despite all the turmoil in its ownership.
[OP] ejboy | 19 hours ago
kodebach | 10 hours ago
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.
za3faran | 5 hours ago
[OP] ejboy | an hour ago
pjmlp | 15 hours ago
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.
ksec | 13 hours ago
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.
rjrjrjrj | 6 hours ago
alfiedotwtf | 20 hours ago
papercrane | 20 hours ago
There is also JavaFX, but that is no longer bundled with the JDK.
fian | 18 hours ago
TeaVMFan | 20 hours ago
* React replacement: Flavour ( https://frequal.com/Flavour/book.html )
* Vanilla JS equivalent: TeaVM ( https://www.teavm.org/ )
Zardoz84 | 14 hours ago
hackingonempty | 15 hours ago
fithisux | 15 hours ago
pjmlp | 15 hours ago
tofflos | 11 hours ago
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?
skissane | 20 minutes ago
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.