the people that work on Java & the JVM are very smart.
it has become a best of breed language - hell its better than Go for industry purposes.
the drawback with Java will always be the CULTURE - (maybe someone can insert a quote of how in physics progress is only made, when old physicist die - I don't wanna be morbid ) but with Java same that's when the culture will change.
All those people using typescript (could be using Java - but the culture doesn't want them and consider them heretics for not embracing religion of OOP and FactoryFactory)
> for not embracing religion of OOP and FactoryFactory
Not the case today. Of course, crappy code (or questionable patterns) can be found in all languages, and java community had made some innovations in the area early on, but today we have a different picture.
FactoryFactory has gone mostly extinct, the most likely place to see it is “dailywtf.com”.
We now know that we prefer composition over inheritance, we have stream api - language and community evolved, old patterns are not neccessary anymore to solve same/similar problems.
> We now know that we prefer composition over inheritance
When people say "composition over inheritance" in Java discussions, they usually mean the trivial modeling rule: prefer has-a over is-a.
But that’s not what composition is really about.
The deeper idea is interface composition -- building types by composing multiple behavioral contracts behind a single cohesive surface.
Java provides inheritance and interfaces, but it doesn’t provide first-class delegation or traits. So most developers never really practice interface composition. They either subclass, or they wire objects together and expose the wiring.
The slogan survived. The concept mostly didn’t.
The manifold project, for example, experiments with language-level delegation to make interface composition practical with Java.
> Java provides inheritance and interfaces, but it doesn’t provide first-class delegation or traits.
I'm not sure I am missing first class delegation much (not a lot of UI projects in Java these days).
But interfaces with default (and static) method implementations are actually quite usable as traits / mixins. Since Java 8 IIRC.
You can also pass around functions / lambdas (coincidentally also since Java 8) to compose functionality together. A bit harder to follow and/or understand, but another perfectly legitimate and very powerful tool nevertheless.
How does a type class help with composition? They do help with the expression problem (adding support for an "interface" after definition), and via parametric polymorphism they might give you a bit with regards to composing two traits.. but you do also have generics in Java, even if not as good as type classes.
So anyways, I don't see as big of a change here. But there was a Brian Goetz mail/presentation somewhere where he talked about adding "basically type classes" to Java? But unfortunately I couldn't find it for you now.
Kotlin's "delegation" feature isn't true delegation, it's just call forwarding, which is better than nothing, but it falls down pretty quickly as an alternative to implementation inheritance.
The manifold project provides true delegation[1] for Java.
it really depends on your project, and what framework(s) and libraries you choose to use.
Java still has a tonne of legacy projects using old(er) frameworks that rely on such patterns - spring has some old versions which is like that, and i am certain plenty of java projects are retaining those old versions due to lack of desire to upgrade.
If you're starting a greenfield development in java, you surely would not befall into that factoryfactory pattern (unless you're just copy/pasting old projects around...). But i imagine there's way fewer greenfield projects compared to older projects requiring maintenance.
It's still going to be hard to overcome the stigma of ex-Java developers coming into other languages and bringing their overly complex ideas with them. But I am happy to hear Java itself is evolving and I hope that limits the downstream effects of it being one of the most popular language a lot of devs start on.
It's getting better, it doesn't all have to be Spring Boot and JBoss.
There is quarkus, helidon and micronaut for slimmer more modern backend frameworks. jbang for scripting (think uvx, bunx), Tambo UI (https://tamboui.dev/) for terminal UIs, and more.
Along with all the new Java features that help you write much simpler code - eg. virtual threads, structured concurrency, stream gatherers, and performance / resource improvements.
It's not all there yet, but I think the next few years things will come together nicely (however a better build system is sorely needed - one of the things that Go / Rust did right).
I've found it quite satisfying compared to the other "new" ones.
As for the original topic, I just want to echo what others have said, and say that I am happiest in Java when writing it as if it were Golang code. That an the first-class runtime and performance and deep ecosystem make it a great choice in 2026.
It’s still very much an annotation festival in the code, making the framework quite lengthy to learn for newcomers (gotta learn Java and the whole quarkus annotation DSL with it).
Go is verbose, but it is much more explicit and only uses standard language things instead of a whole annotation DSL.
In my opinion Helidon is the most refreshing of these frameworks. It supports virtual threads from the ground up and comes with clean, function, mostly annotation free APIs. It really looks like a Java framework should look today.
There are non-DSL frameworks in Java. It's just that arguably the benefits of a DSL outweigh learning them.
Putting an annotation on a method is much easier than registering this method at n places in ordinary code, which could look any number of ways. If you move to a new project, in the first case can just immediately jump into framework-related stuff, while in the second all this logic has to be untangled first. And let's be honest, Spring/Quarkus probably got their abstraction right after n iterations, which is not necessarily true of a random team.
If someone reads this and wonders what JBoss is, the contemporary variety is called WildFly and it is actually rather easy to install and play around with.
As you’re familiar with the JBoss space, why would someone use an enterprise container over a simple HTTP server (Tomcat, Jetty, etc)?
Currently I’m trying to externalize as much as possible to the service mesh. I want teams to stand up a basic unencrypted HTTP server that accepts the company headers and just works with as minimal of a runtime as possible.
I wouldn't use application servers today, but they were solving many of the same issues as whole kubernetes clusters do, decades ago.
The Java (now Jakarta) EE standard on top is a good base for third party implementations to "speak a common language", e.g. it's not that hard to move between Quarkus/spring/micronaut etc, even if not all support the actual standard.
Yep, I'm using JBoss as a catch-all for older "big-iron" style Application Servers - modern Jakarta EE (10 onwards) is much more slimmed down, and a solid option.
unsure re Maven, 4.0.0 has been around the corner for years, but I think there is space for a modern alternative that is JPMS first, supports semantic versioning (i.e. tilde/carat notation) with lockfiles, and doesn't require a bunch of plugins out of the box for common use-cases. Maybe Mill (https://mill-build.org) - i've yet to try it.
Mill looks kind of nice on the surface but I haven't seen it in action in any serious project. I suspect the flexible DSL might come with a maintenance burden.
XML is nice, if your pom.xml is massive, just suck it in through JAXB and program against it, perhaps render it to a web page. XSLT can also be helpful. We're not supposed to look at XML as plain text.
Not really, no. It is similar but worse than Maven in that it requires quite a bit of time investment to configure, and shares the drawback of Gradle that it is configured in a programming language instead of a configuration language.
Switching out Maven for a larger maintenance burden might be reasonable in a large organisation that is swimming in competent employees, but most do not.
As for obvious contender, I'd say that would be Gradle, which is harder to get someone started with than Maven and due to the DSL allows you to invent weirder footguns.
Did everyone just agree to forget about Gradle? It was everywhere not too long ago. I think I even prefer it to Maven, in a choice between a rock and a hard place type of way.
Yeah, same, but Elixir gigs aren't as common as Java gigs. However, if one ends up in a Java role, chances are that Elixir would be a good porting target for the systems since it typically can replicate the architecture but with less fuss and has pretty good support for interfacing with Java.
Nobody ever wanted to wire up RPC endpoints, in the form of Enterprise JavaBeans(tm), using XML files. That is one for the history books of ridiculous technology.
XML files are bad. Invisible magic is worse. The sensible way to wire up a bunch of RPC endpoints is, like the sensible way to do most things, plain old code.
Having used micronaut for a few years now, I hate it.
Maybe it's innate to trying to use a a fully fledged server-style framework in a serverless context, but I don't think it's suitable. In fact I think the whole idea ("Hey, let's bludgeon spring-like metaphors into an entirely new setting") was a poor one.
Java itself I've enjoyed more and more over time as the language has evolved into something much more expressive, and without all the enterprise crap. My hope is that one day frameworks like Micronaut will end up discarded too.
Never done much Spring, so I don't have a lot to compare to. But ...
I'm not a massive fan of using annotations in concept, because they obfuscate what's taking place. Unlike in (say) Python, where annotations are effectively functions wrapping the function they annotate, in java they're more akin to a customisable preprocessor. Obviously I do use them, liberally, because that's the way things are done, but I'm not a big fan. And using any modern framework relies on these a lot.
Micronaut gripes -
1. It works great until it doesn't, and you have a special case, and then you have to dig into source to figure out what on earth is going on.
2. Keeping up with latest isn't always easy, micronaut 3->4 was a huge effort.
3. For all it's called micronaut, the produced packages are pretty huge.
Serverless-specific gripes -
1. What I'm receiving isn't really an http message over a socket. It's an AWS gateway event with everything already read and packaged up. So there's no reason that (for instance) I shouldn't access the message body in a request filter, because I don't give a crap about the jetty server-loop being non-blocking.
2. Startup time is terrible. And when I managed to get a native compiled version to actually run, it got worse. A lot of this seems to be down to hibernate, but there's a big gap between startup and any logging from the framework at all. We've tried a bunch of stuff to remediate, so far with little success.
In general I think that serverless is such a different paradigm from a long-running server that approaching it from the point of view of "how can we make this the same so developers who've never thought outside of the spring-like box can still be productive?" was wrong from the outset.
> Unlike in (say) Python, where annotations are effectively functions wrapping the function they annotate, in java they're more akin to a customisable preprocessor.
I find that Python decorators can do as much magic as an annotation processor - due to the dynamism of Python. Annotation processors, in most cases, produce a new class based on annotations on existing class / interface. The injection of that class is done by the DI container (unless it's a standalone annotation processor like mapstruct).
> And using any modern framework relies on these a lot.
To be fair to language designers, it's hard to avoid code generators. And they're a compelling thing compared to building proxy objects / DI / decorator / dataclass etc.. kind of functionality in language and getting it wrong.
> ... then you have to dig into source to figure out
Agree. It's not a "boring technology" yet.
> For all it's called micronaut, the produced packages are pretty huge.
How huge? And jlink or graal vm? Just curious.
> A lot of this seems to be down to hibernate,
With micronaut atleast, I remember using Micronaut Data JDBC. Anything is better than hibernate.
> In general I think that serverless is such a different paradigm from a long-running server.
> a better build system is sorely needed - one of the things that Go / Rust did right
Honestly there are only two reasons I wouldn't pick up Java for personal projects, difficult to build single executable (Graal is still very un-ergonomic), ridiculous build systems.
I can kind of live with former, but Gradle is so very extraordinarily terrible that I don't know where to begin. Problem is, it solves some real problems (in extremely bad way) that people keep using it.
I long of a cargo-style revolution in Java world. (No, the newly popped up alternatives haven't really cut it so far)
After ~13 years of working with C#, I moved to Kotlin. It's such a beautiful language. When I have to read docs for a Java lib I realize why I like Kotlin.
I want to say culture around Java doesn't have to change, new culture is growing around succinctness (if not simplicity) of Kotlin, and it gets most of the benefits of Java ecosystem.
I get the snark, but also - there is this "ideal Java code style" that most experienced devs tend towards. Unfortunately I don't see anything like that for Kotlin (yet?), and there are a bunch of patterns that I really dislike. I sometimes feel people just toy around, like "wow I can make this into an extension method, how cool" and leave that as the code.
In general, I really dislike extension methods, especially when paired with tiny objects with barely any functionality to begin with. Like people build a mental model of what a thing is based on how can it be used - but if you leave that empty and put every behavior at different files in the form of extension methods you make this understanding very hard to build up.
Add to it that it removes polymorphism and often actually hinders readability.. so my point is, having more ways to write code is not necessarily a positive.
I must say I prefer C# over Java. They're pretty similar in a lot of ways, but LINQ is much nicer to use than the Java streaming equivalents. And there are some odd warts like Java lacking unsigned types.
I wonder if at we are standing looking at the smoking field of programming languages created over the last 50 years and gazing at the final survivors, of which Java is definitely one.
Why would anyone create a new language now? The existing ones are "good enough", and without a body of examples for LLMs to train on, a new language has little chance getting traction.
I learned IBM /360 assembler when I started in computers a long time ago. I haven't seen a line of assembler in many decades, but I'm sure it's a viable language still if you need it.
Java has won (alongside many other winners of course), now the AI drawbridge is being raised to stop new entrants and my pick is that Java will still be here in 50 years time, it's just no humans will be creating it.
I'm writing my own programming language right now... which is for an intensely narrow use case, I'm building a testbed for comparing floating-point implementations without messy language semantics getting in the way.
There's lots of reasons to write your own programming language, especially since if you don't care about it actually displacing existing languages.
Most of my 20 years of experience is Java. Now 3 years into a new job mostly using Python to build microservices. I feel much more productive using Python (plus uv, ruff and mypy for fast repeatable package management, linting and type checking). I see Python having a trajectory to keep improving and gaining more adoption - eg Python keeps growing in popularity https://survey.stackoverflow.co/2025/technology/. It will have real threads soon and better type checking with ty (thanks to astral who also make uv and ruff). Python gives an incredibly tight integration loop since you don’t wait on compiling. Our kotlin projects are always at least 2x slower for ci/cd builds. I like typescript, but working with it in IntelliJ is incredibly slow.
What advantage do old languages have that can’t be overcome or at least reduced to insignificance?
The 50-year head start in training data, runtime, and ecosystem? That may not be much, because LLMs are rapidly accelerating software development. LLMs can also generalize: take what they learned for one language and apply it to a “similar” language (and I think most modern languages are similar enough for broad effective translation: all have records/unions, objects, functions, types, control-flow, exceptions, and more). Some fairly recent languages (e.g. Rust, Swift) already have comparable runtimes and ecosystems to older ones, from human-driven development acceleration and concept generalization.
In a recent study, LLMs solved the most exercises in Elixir (https://autocodebench.github.io Table 4). Anecdotally, I’ve heard others say that LLMs code best in Rust, and (for UI) Swift. More importantly, I don’t see an older language advantage that is widening from LLM use; an older language probably is better for most use cases today, but any written code can be translated or regenerated into a newer one.
> Why would anyone create a new language now? The existing ones are "good enough", and without a body of examples for LLMs to train on, a new language has little chance getting traction.
Compiler writing can be an art form and not all art is for mass consumption.
> Java has won (alongside many other winners of course), now the AI drawbridge is being raised to stop new entrants and my pick is that Java will still be here in 50 years time, it's just no humans will be creating it.
This makes no sense to me. If AI possesses intelligence then it should have no problem learning how to use a new language. If it doesn't possess intelligence, we shouldn't be outsourcing all of our programming to it.
Intelligence is not a well understood concept. "AI" is also not a well understood concept - we have LLMs that can pick up some novel patterns on "first sight", but then that pattern takes up space in the context window and this kind of learning is quite limited.
Training LLMs on the other hand requires a large amount of training data.
> This makes no sense to me. If AI possesses intelligence then it should have no problem learning how to use a new language. If it doesn't possess intelligence, we shouldn't be outsourcing all of our programming to it.
Perfection. You have made such an excellent. However, I don't want to detract from that but it's like, in reality, this is a completely obvious point but because of this AI/LLM brain-rot that has taken over the software programmer community, writ large, this is particularly insightful. It's also just a sad and unimaginative state we are in to think that no more programming languages will ever be needed other than what currently exists in March 2026 because of LLMs.
Programmers would create a new language when there is a fundamental change in hardware architecture such that the assumptions underlying the old programming languages no longer apply. Java is probably a poor choice for writing software in which most computation happens on GPUs. But I agree that someone (or something) will still be using Java to write new line-of-business applications in 50 years.
Same reason you'd ever create a new language — to start anew, breaking free from the shackles of backwards compatibility of the old language, having learned the lessons of the past.
The AI angle makes even less sense — surely we will want to create languages that
are tailored for them.
As a Go developer, this is right on the mark. I’ve been hearing good things about Java lately, so I decided to check out the language for the first time since 2012 or something. And I was impressed!
The language maintainers have added so many great features while maintaining backwards compatibility. And slowly but surely improved the JVM and garbage collection. So after toying around for a bit, I decided to write some personal projects in Java.
After a week, I gave up and returned to Go. The build tooling is still an over engineered mess. Third party library APIs are still horrible. I will never invest even 5 minutes in learning that horrible Spring framework when stuff like Django, Rails, or the Go ecosystem exist.
The community, and thus the online forums and open source libraries, still approach engineering and aesthetics in a way that is completely foreign and off putting to me.
> Spring framework when stuff like Django, Rails, or the Go ecosystem exist.
Django and Rails have a very similar model to Spring, so frankly this is just "I was lazy to learn a new tool and it must suck" kinda take. Is there a learning curve? Sure. Does it worth it? I would say for typical CRUD stuff, yeah. No matter how trivial it is you will likely end up needing something that is a single annotation away. But you may want to try quarkus over spring.
What do you mean by "better than Go for industry purposes"?
I don't understand what "industry purposes" means and in what aspects Java is better than Go in your opinion (I can think of some myself, but I'm interested in your perspective).
Not the GP, but for really large code bases, Go is missing a few features that I've noticed:
1) No immutable types. My work team is a huge user of immutable data stuctures in Java to make sure data passed around to other teams isn't changed. Go doesn't really have a good way to do this.
2) Refactoring can be really annoying (or at least really noisy) because of public/private being defined by capitalization of method/field names.
3) Error handling isn't great. I love Go's errors being just normal values, but the `error` interface is awkward when trying to figure out what kind of errors can be thrown without having in-depth knowledge of the kinds of errors that can be returned. We regularly need to make different decisions depending on the kind of error returned. Knowing which errors can be returned in Go is not defined by the method being called (only in comments).
> However complex error recovery is an anti pattern for Go.
Bit of snark from my side, but that's exactly what makes it less good of a fit for "industry purposes".
Go's error handling is possibly the worst out of any "modern" language, it basically copied C's errno which is not something you should have ever done.
This was exactly my experience when I first read about Go. I was so excited until I found they were repeating the c experience of check every bloody return value separately. That was the worst feature of c - why copy it
Because almost my definition you can't handle errors in the component, otherwise you would have a conditional and not an error.
E.g. if I do some IO like "make a copy of these files" and get an error/exception, it's only the caller or maybe even that caller's caller that can properly deal with this condition (e.g. to decide that we will skip the erroneous files or retry).
Hey it's better in Go. In Java it's getFoo(). In Go it's just Foo(). Saves three bytes, and three keystrokes if you program by hand and don't autocomplete!
This is not a dig at Go and this will be controversial but I so struggle to see what problem or area Go is solving outside of CSP. It's a nice language it just feels far too simple and I am really convinced of it as a systems language over Modern C++ and if you want that alternative then we have our rather oxidized friend that seems to more substantial. That's just my take.
I code Go at work. I've been using it for just over 3 years. I really like it. I prefer Java, but Go is a much more ergonomic C and its a very pragmatic language. Except for the *%!@ error system, that can burn in hell.
No, not just like. You're downplaying significant differences between the two that do in fact matter. So much so in fact, that you're just wrong. Stop spreading misinformation.
Go use cases overlap the most with Java. I think the reputation you mentioned comes from Google using a lot of C++ for high-level things others would likely do in Java, so they see Go as a replacement for C++ in some areas. (assuming you meant C++ not C)
It's replete with oddities and limitations that signal "ah, this is because systems language."
Go’s type system, for example, is very much a systems-language artifact. The designers chose structural typing because it was lighter weight, but provided enough type safety to get by. It sucks though for enterprise app development where your team (and your tooling) are desperate for nominal typing clarity and determinism.
The error handling is like a systems language for sure, I'll agree on that.
But where do Go's docs or founders call it a C replacement? gf000 asked where this is mentioned besides marketing, but I don't see it in the marketing either.
Ya, that seems to be a misunderstanding. "Industry purposes" covers a huge range of stuff. Go is pretty good for systems programming where Java isn't really an option due to the fundamental limits imposed by garbage collection and lack of pointers. Java is pretty good for higher-level application development where occasional GC pauses are tolerable (the GC pauses are rare and fast now, but they still rule out using Java for certain purposes).
Are you sure about Go's garbage collector doesn't have pauses? AFAIK they are worse than modern Java's garbage collector [1].
I'm not sure it's even better than Java's, especially for modern ZGC (and you can choose your GC in Java). Definitely less configurable. I would say most of online comments about Java's GC are long outdated.
For example, in web servers a lot of work is request-response, so it's convenient to utilize generational GCs (so that each request data would fit into "young" generation). Similar to arenas, but without code changes. Go's GC is not generational though, so you should care about allocations.
Hell, I even had a use case where serial GC was actually the correct choice (small job runner process that needed to be extremely low memory overhead). It's nice having options, and most of those options are extremely good for the use cases they were designed for.
Ok, which one do I choose then, with what configuration? How much time do I need to spend on this research?
How do I verify that they are actually better? Is the overall performance of my program better? Because that's what I care about. I of course do include memory usage in "performance".
> I would say most of online comments about Java's GC are long outdated.
They are not. Feel free to look up literally any half-decent benchmarks. If Java's on par or better than any other language of note, check the memory usage. It's standard for Java to have 5-20x the memory usage for about the same performance. The memory floor also seems to be in the hundreds of megabytes. Ridiculous.
> For example, in web servers a lot of work is request-response, so it's convenient to utilize generational GCs (so that each request data would fit into "young" generation).
No, that's a job for arenas. Generational GCs are mostly a result of Java's limitations, and not a univerally good approach.
> Go's GC is not generational though, so you should care about allocations.
You should always care about allocations. In fact, the idea that you shouldn't is a big part of Java's poor performance and design.
No-one ever claimed that Java didn't use a lot of memory. The "comments about Java's GC" used to be about pauses, mainly.
Java programmers don't claim that the JVM is conservative with memory use.
That said, 5-20x.... nah. Maybe for a toy 'hello world' sized program, but not in real usage
The "reasonable" thing go does is pausing core threads doing the actual work of your program, if it feels they create too much garbage so it can keep up, severely limiting throughput.
I think this is a misunderstanding. If the program out-paces the GC because the GC guessed the trigger point wrong, something has to give.
In Go, what gives is goroutines have to use some of their time slice to assist the GC and pay down their allocations.
In Java, I believe what you used to get was called "concurrent mode failure" which was somewhat notorious, since it would just stop the world to complete the mark phase. I don't know how this has changed. Poking around a little bit it seems like something similar in ZGC is called "allocation failure"?
The GC assist approach adopted by Go was inspired by real-time GC techniques from the literature and in practice it works nicely. It's not perfect of course, but it's worked just fine for lots of programs. From a purely philosophical point of view, I think it results in a more graceful degradation under unexpectedly high allocation pressure than stopping the world, but what happens in practice is much more situational and relies on good heuristics in the implementation.
A lot of the answer is that if you can do more work while generating less garbage (lower allocation rate) this problem basically solves itself. Basically every "high performance GC language" other than Java allows for "value type"/"struct"s which allow for way lower allocation rate, which puts a lot less pressure on the GC.
How much less allocation rate? Value types are an important thing and fortunately they are coming to Java as well. But they don't decrease allocation rates nearly enough in every kind of software. They may be a necessity in games/certain computations/low-lat trading, but for a typical web server they don't matter all that much - people are using identity having objects in value typed languages the same way here. Especially that with thread local allocation buffers in Java single-use object allocations are not particularly expensive to begin with - live objects are evacuated and then the whole buffer is reset.
So unless you claim that there is no software in Go/C# where the GC is the bottleneck, no, the problem absolutely doesn't solve itself.
And yet Java outruns pretty much all of them, because it doesn't actually allocate everything on the heap all of the time. And you've been able to declare and work with larger structures in raw memory for ... 20 years? You mostly don't need to, but sometimes you want to win benchmark wars.
And of course it's getting value types now, so it'll win there too. As well as vectors.
Backwards compatibility, every vim and emacs and bash enthusiast should know about it.
It's easy for the USER to fix, since there are flags available. In the day of LLMs it's also easy to find out about those flags and what they do. And if it's so important, testing shouldn't be supremely hard, either.
Do you mean backwards compatibility for things that rely on the default settings? The defaults have already changed across Java versions and also depend on the system.
Normally when you run a non-Java binary, it uses very little memory to start, doesn't have a limit, and returns memory to the system when it frees things. Supposedly you can set JVM flags to do all that, but performance probably suffers, otherwise they would've just done that. So in practice users are always setting the flags carefully.
I write TypeScript daily and honestly it is not about being scared of Java. The ecosystem just makes more sense if you are already building for the web. You write your frontend in JS/TS, your backend in the same language, your build tools understand it natively, and you share types between client and server. That is a hard thing to replicate in Java even if the language itself is technically better in some areas. The barrier is not cultural fear, it is practical convenience.
With SSR/HTMX/HATEOAS the amount of code executed on client side is relatively minor and does not justify the unstable JS/TS tooling and frameworks, and the security nightmare which is NPM-based supply chain.
Different tools for different purposes...which is good/right.
TypeScript is a superior programming environment for the browser, for sure.
Using it on the server? Why not, if you're not trying to scale (in capacity, or functionality).
Language-agnostic serialization exists for a good reason. It's not always right, but it's almost always the right thing to do.
What if you have a mobile app? Rest APIs? The argument doesn't work. Every backend language has ways to generate specs/types/clients from the APIs code.
> You write your frontend in JS/TS, your backend in the same language, your build tools understand it natively, and you share types between client and server.
that's an excuse imho. It's a post-facto justifying using js on the serverside because of familiarity.
I know because the exact same reason was given for GWT (google web toolkit), and that failed pretty horribly (despite it being quite good imho).
Yeah, I believe some ex-Googlers even claimed that writing Gmail was simply impossible at that time with ordinary JS, and the abstraction behind GWT was an absolute necessity (though maybe the frontend part was not all that important - closure compiler is still alive though)
On the other hand, gwt did not gain much traction, and the majority of frontend developers disliked it (granted, they do prefer javascript+css rather than coding the frontend via gwt widgets).
The biggest problem with Typescript in the modern era is that LLMs are pretty bad at it, at least as compared to some other languages that are more well suited to LLM generation. What you say may have been a boon in the olden days, but it is hard to justify now. It is difficult to avoid Typescript/Javascript in the browser, sure, but now it's just as fast to duplicate everything in another language for the backend and at least gain the advantages on that end.
Maybe this is just a question of taste but I never could get along with Javas (or Kotlin's) tooling.
Primarily working in Vim/Helix works for most languages from Nix to Typescript or Rust and C, but Java just never worked quite right. It also generally felt like it had a worse story around tooling from a DX perspective, something like Golang or even npm feels a lot lighter than the molasses of JDK management and gradle et al.
No, I'm not. Through university (and even before) I have access to their full suite. I have tried to use PyCharm, GoLand and Idea.
Idea was useful for Java but felt quite slow and even with vim bindings was a pain to navigate. Learning the shortcuts helped but it never got quite as fast as helix/vim for general editing (especially as my work usually is a polyglot). It might be the best for Java (compared to eclipse or bluej) but that does not mean it fits my workflow/way of work.
PyCharm/GoLand both are "nice" but it did not feel better/more efficient than pylance/pyright)/gopls + vscode/helix. The only I still occasionally use is DataStorm as it is quite a nice SQLite/PostgreSQL client.
Besides doing yourself a disservice of not using a proper IDE, what exactly makes Java not writeable in vim or the like? Like it's a pretty simple language with not much magic going on.
And Java has some advantages that are hard to beat. It performs better than Go and builds just as fast (at least when not using some popular build tools) while offering unmatched deep, low-overhead observability.
People might think they may enjoy another language more, but the portion of people who eventually come to regret choosing Java is probably lower than that of any other language.
Do you have some sources or experiences to share on this topic? I'm very curious. My experience is the complete opposite.
At my previous job there was a Java web application and running in Kubernetes (1 vCPU and 1Gi of memory) was able to deal with at most 80 requests per second, using up almost the full 1 vCPU and ~600-700MiB of memory. That was a bit disappointing, since we were supposed to support at most ~1000rps on this API, 13+ pods is a lot, and we felt "software could do better".
A reactive guru from another team told us we should use a reactive stack, so he came in and rebuilt the app using the reactive stack. Now it was doing about 120rps on one pod (about the same memory usage), which was a good improvement, but still disappointing.
One guy on the team was motivated to rewrite the API in Go as a proof of concept, and we were blown away. With the same 1 vCPU it was now able to handle 400 requests per second, while using ~100-200MiB of memory, and having approximately 20% better response times.
> builds just as fast (at least when not using some popular build tools)
I find this a little bit of a cop-out, because almost everyone is using the popular build tools. And it's quite a chore to build a full application without those popular build tools. With Go, all batteries for building are included.
From your description it sounds like you're comparing an old Java program running on an old JDK with a new Go program running on a new Go runtime. These days Java has virtual threads (similar to Go's goroutines) and doesn't need a "reactive stack", and its optimising compiler and GCs blow Go out of the water without breaking a sweat.
I mean, what is old? How far along are frameworks these days, and what are companies using?
That team was using Java 17. Java 21 was just released and frameworks had no meaningful support for virtual threads whatsoever.
In my experience, most companies using Java are chronically multiple versions behind (e.g. some of my friends still in the Java world are on 11).
Perhaps you can share some sources which prove that Java's performance blows Go out of the water without breaking a sweat? I have not seen any such articles about that in the past 3 years, besides the cherry-picked cases where the JVM JIT can optimize some small algorithmic part of the program on the fly (which is not relevant in most web applications).
I'm happy to stand corrected.
Edit: I found this one using a quick search myself https://medium.com/@mohnisha/java-vs-golang-performance-test...
I'll check it out and see if I can reproduce it myself too. Still too bad about that gargantuan memory usage, but I guess memory in the cloud is cheap.
Sorry I have to defend my pride here a little bit. When I joined my previous company, the entire company was on Java 8. When I left every app in every team there was up-to-date on the latest LTS release at the time, 17. I assisted many teams in upgrading their Java, Spring, etc, and inspired even more.
I would argue that I'm one of the last people who you could blame for most companies being many Java versions behind...
So what's the issue then? You'd be able to bring other teams to current versions of Java and frameworks, which have all been using virtual threads for the past 3 years.
Yeah javac is pretty great. I was doing Kotlin for some time and I was getting very annoying by how much slower and slower running tests and doing full builds became. I thought it was some issue with the JVM ecosystem. Then I started a project with pure Java and I was blown away by how fast it was. Unit tests in my IDE running as fast as I'm used to in Go. And indeed I was surprised by the speed of the compilation step of the build too. Perhaps Kotlin is doing better now, haven't touched it in a few years, but yeah, Java made some great steps there in the past decades.
Use javac directly, in a recent JDK, to compile lots of files at once (i.e. one invocation of javac to compile multiple files) and you'll see. The speed is over 100,000 lines/sec: https://mill-build.org/blog/1-java-compile.html
I dont think the Spring ecosystem is bad. In fact, its one of the more stable frameworks. Even spring AI which is built for AI agents a new use-case is very intuitive if you take time to learn its abstractions. Usually doesnt take more than a day of reading docs and writing some try-out code. The thing I really like about Java is the stability of its packaging ecosystem. Maven is XML (yuck) but is okay with the IDE integrations. Gradle has advanced features often missing in Python / Go such as build caching. The OOP stuff is also good because it scales with very large code bases. In, fact frontend esp React adopted a functional style which leads to complexities associated with hooks. A mixed approach is usually better. Overall, the only bad thing are the multiple unnecessary abstraction layers which are a pain in any language. Rest of Java is quite good.
The counterpoint is that Java has so much SOTA GC work precisely because the language makes writing efficient code that doesn't heavily tax the GC basically impossible.
Tell me you haven't looked at Java in 15 years without telling me.
Given that the vast majority of non-GC language code does a terrible job of managing memory, it's not difficult at all for the JVM to win out on efficient, reliable systems.
To be clear, I think that GC is absolutely the right approach, you just need an object model that lets you write idiomatic code that allocates an order of magnitude or 2 less. Once Valhala is (finally) released, the Java ecosystem will start to have the tools to write efficient code (the same tools that C# has had for ~2 decades now), but until then it's just completely impossible to write object oriented code in Java without millions of allocations per second.
I would love to have a Java compiler with the capabilities of the .net compiler. To make incremental builds to aid code completion including type information, looking past simple syntactical errors, fixing them, and continuing compilation.
Currently, this is “magic” embedded in eclipse, IntelliJ, and maybe a bit in the vscode plugin. Imagine having a Java LSP running that can provide all this information while typing.
.net has had this for ages. From a language design I think that is wonderful.
It also slows VS code a lot, is not properly documented, and still relies on concatenating strings together, due to Source Generators interaction with attributes.
On the contrary, as someone that earns their bread using both ecosystems, .NET is still pretty much tied to Windows, regardless of .NET team efforts, most shops going with macOS or Linux are former Microsoft shops saving on server licenses or giving Macs to their devs.
There are many platforms where .NET doesn't have an implementation, a phone to call their own (even if ART isn't proper Java, WP is no longer around), embedded systems, including factory and military weapons deployments (PTC, Aicas, microEJ), copiers (Xerox, Ricoh), phones (Cisco),....
C# is definitly better than Java dealing with value types and low level programing, or being embraced by the game development community, however not sure if the featurities of last years is the right path, I am starting to feel I should just reach directly to C++ instead.
Bright future for it just means it is not planning to become 40th or 400th.
(My prediction - in next ten years java will always be among top 6; new language might come to the very top and some leapfrogging game between c# and java)
Enterprise space architecture is not picky, all programming languages get a place when they manage to hit big at corporate life.
It can be Yourdon with C and Pascal, Booch with Smalltalk and C++, Patterns with Smalltalk and C++, UML with Ada, C++, Smalltalk and Java, Rational RUP , Java and .NET application servers, Kubernetes with WebAssembly microservices,....
Ever looked into Typescript with effects, pretending to be Haskell?
> All those people using typescript (could be using Java - but the culture doesn't want them and consider them heretics for not embracing religion of OOP and FactoryFactory)
I assume you're specifically talking about the backend and not suggesting that people write Applets or use GWT or something.
Says a single guy who may have coined the term, but that's not how words work. The industry's millions of devs use it differently, so the de facto meaning is that java is an OOP language, and the original is closer to the actor model.
The problem is that many jobs with Java (that I've found) lean so heavily towards OOP that it's part of the job description. I just don't enjoy OOP and find that there's almost always a simpler approach, and to have it prescribed as part of the engineering culture will always steer me away.
Most of backend development on Java is procedural with OO syntax and ability to replace something in the chain of calls with stub in tests. Spring beans are usually stateless singletons containing a few references.
Yep, I find it easier to think of a Spring (or any DI) Bean like a parameterized module that is applied at runtime, the code within each bean is pretty procedural.
Front page, 82 comments, comment 2 hours ago…why is this the top comment? “People who write Typescript could just be writing Java except they’re scared of being outcasts for not using design patterns” is bait, not a serious technical opinion.
Yet if you ask people in the bay area, especially the those who are under 35, they would tell you that "Use Java? Over my deadbody". It's just amazing that people always chase shiny new things.
> hell its better than Go for industry purposes. [...] the drawback with Java will always be the CULTURE
The industry purpose for Go is that all codebases look more or less the same, so workers can jump into any project they've never seen before and instantly feel like they wrote it themselves. Google talked about that a lot around the time Go was released. It is why they created it instead of just adopting Haskell or something.
Some of that simply comes down to the language not allowing much creativity, but without the culture developers would still find a way to mess with outcomes. You can still write crazy Go code if you want to. The culture is the piece that matters. If Java doesn't have the culture, how does it fit in industry?
With all due respect, I'm fairly sure that anyone using "VM" the same way as you do here really think of it as a container or what.
It's a runtime, and go also has a similar, fairly fat runtime. It's just burnt into the binary instead of being shipped separately. (Hell, even Rust has a runtime, it's just very very lean compared to languages featuring a full GC like go and java)
With LLMs as they currently stand, and with the reasonably confident hope they will get better why even have anymore languages. Shouldn’t we just have everything coded in the most performant language which would be Assembly or C?
I didn't use Java since 7, but from people that do - nowadays you basically don't code Java, you code Spring Boot. And that has all the bad things you think when people say "Java".
Spring Boot isn‘t bad. It‘s opinionated about configurations and dependencies. Its main advantage is that you can start shipping production-quality code very quickly, focusing on business problems rather than anything else. Vibe coding on it is more or less stable, entire apps can be built solo in a few months. And it‘s easy to do fullstack with SSR based on Thymeleaf and Htmx. It is absolutely superior to anything that exists for node stack.
And then there‘s also Micronaut, if you prefer compile-time setup to Spring.
There are more Java devs than people in my home country. Like how could you even give a single description for all of them? They all work on vastly different stuff, from low-latency trading to robotics, to regular old CRUD. Not even the CRUD part is as monotonic though as you make it out to be.
There's a lot of programming that has nothing to do with SpringBoot - and I say this as someone who works in a backend team that uses SpringBoot for all our apps.
A completely different culture of Java usage can and does exist a lot of places. It is absolutely true that success creates a certain ossification of practice. But SpringBoot is not necessary, any more than Guice or any other framework-y thing.
That's weird. Back when Java 7 was a new thing, people used Spring (Boot wasn't there yet) even more to compensate for the lack of language features. Also back then most projects still used XML configuration, so you actually write more Java code in modern Spring. Because Spring Boot uses Java configuration classes by default (although you can still use XMLs if you need for some reason).
> Nowadays you basically don't code Java, you code Spring Boot. And that has all the bad things you think when people say "Java".
Subjective experience, but largely agreed.
Vague rant that summarizes my own experience: major version updates kind of suck, even if Spring Boot is still better than regular Spring (I've gone through the XML hell, was not fun, even less so with a separate Tomcat instance that we had to deploy to, instead of an embedded one). In practice their huge effective pom.xml also leads to conflicts when your package needs something else and it feels a bit arcane to override things. There are things that have underlying technical reasons for being the way they are but seem stupid from afar - like how @Transactional doesn't work when called from within the same bean. Personally I also prefer code over convention for configuration and initialization so the whole annotation driven setup feels quite annoying and difficult to debug when things go wrong - but even the code configuration isn't always great and sometimes it feels like they have abstractions for the sake of abstractions. Spring Boot also often brings friends like MapStruct or Lombok or Mockito which add even more dynamic behavior and issues when you update JDK, alongside slow testing with JUnit and unpleasant debugging of jumping through numerous abstraction layers. You don't strictly have to, but people will.
I probably should have written down every complaint with exact details (so those could be picked apart as user error) over the years that I've been unfortunately maintaining and building shitty software with Java, but I will say this - modern Spring Boot isn't wholly horrible, it has a pretty rich ecosystem and you can do a lot of things with it, but the overall vibe I get from it ofen can be summarized with "Eww." I'd end up using it because I have to, or because it's a means to an end ("Hey, we need to build an event-driven system to integrate with a bunch of others, you have two weeks"), not because I want to.
For the sake of comparison, I believe that for plenty of the folks even Dropwizard would be worth a look: https://www.dropwizard.io/en/stable/ it is more or less like some glue around a bunch of idiomatic packages in the Java ecosystem and it's not horribly hard to integrate something that you want yourself (e.g. Dagger 2 for DI, at this point I'll take anything that does as much as possible at compile time https://dagger.dev/dev-guide/).
Or, for a more modern spin, Quarkus isn't too bad either https://quarkus.io/ or maybe Micronaut https://micronaut.io/ or perhaps Helidon https://helidon.io/ with neither of those being strong recommendations - figure out what you like for yourselves. For people that have been luckier than me, that might as well be the very same Spring Boot, just on better projects. JVM is a pretty cool piece of tech though, and so are the JetBrains IDEs with their refactoring features and nice Maven integration.
I wouldn't count myself as a JavaScript person at all, and usually avoid it where I can, going to some length, to make pages static, if possible. So I am not exactly in the group of people you are attacking.
However, I am afraid of the Java coder who is decorated as senior, has sway due to their position, and who will tell me, that something, that is a simple function, shall not be a simple public static "method", but must be wrapped in yet another object, which I need to instantiate, because OOP, and because obviously I don't know what I am doing, or because it doesn't fit existing "coding practices/style" or "Java style". I am afraid of the Java coder, who for years has not touched anything but Java, because their jobs didn't require anything else, because so many companies want Java. I am afraid of the one who throws around jargon like "dependency injection" all day, without ever using simple terms, or realizing what those things are looking like in another paradigm.
Lord, please save me from ever having to work with such obnoxious and uninformed, learning resistant people. This actually may be a straw man, but even one such character matching one or more of those traits, seated above at the seniority ladder will make a mess, that everyone else has to live with.
> So I am not exactly in the group of people you are attacking.
I wasnt attacking anyone.
Developers are used to the lack of type-safety in JS, and assume that having to code in a type-safe language is something hard. Ive seen this attitude multiple times, it is a known topic.
The issue you are describing is what the author on top mentioned, the culture. It is not just Java, the "enterprise style" coding has infected other languages too. It is the result of how new developers were educated in a time when for example code performance or code readability were only abstract considerations. I fought that style myself multiple times in the past. But thankfully it is going away now.
We are more or less in "chained function call hell" now.
I mean, sometimes managers are uninformed and say stupid things?
You can use any of the other jdk builds from the plethora of other vendors and have zero interaction with Oracle.
I absolutely hate Oracle as a company, but they've really done a good job with Java stewardship. They actually open sourced the entire language / jdk and a lot of the tooling that used to be proprietary.
They still love to play the old Oracle tricks, so I'd rather not use any of their distributions. But the actual work that they do on the ecosystem has been a positive in my opinion.
You don't have to tell all this to me, or try to convince me. I was just describing what the general attitude is. Oracle's behaviour is a risk, even if Java is open source.
I program in Java for more than 15 years now. I can resonate with people hating the language from it's early days due to the experience with all the enterprisy features and over abstractions. Or confunding Java with the Spring ecosystem. But Java came a long way over the years. It's now what many would call a "modern" language. It's less verbose, has many of the features people find appealing in Scala and Kotlin and it can even compile to native binaries using GraalVM. This made building CLIs in Java feasible. Or lambdas.
I recently worked on a Go project and my task was to make it more configurable at build time and start time (add plugins / addons, make it possible to reuse from other libraries and tools). Turned I had to create *Factory and *Providers, even though I did not want to.
It's easy to avoid "AbstractFactoryProviderBuilder" if everything is hardcoded. Try to make it reusable and extensible, and I bet you write one yourself.
> It's easy to avoid "AbstractFactoryProviderBuilder" if everything is hardcoded. Try to make it reusable and extensible, and I bet you write one yourself.
The first domino is opting for OOP. AbstractFactoryProviderBuilders are just the inevitable downstream consequence of that initial choice. No need for factories if you don't traffic in objects in the first place.
Mmm, no, I don't see why OOP has anything to do here (any examples?).
I did not use any inheritance. In general I would say OOP craziness faded long ago (in Java too), together with XML. Interfaces -- yes, are very much alive though.
I'm not using OOP to mean presently unpopular facets of OOP, to the exclusion of presently popular ones, I mean all of OOP. It's pretty hard to need factories, let alone factory factories, when one isn't using objects or classes.
A friendly joke in response to the claim that sufficiently complex code always ends up sprouting OOP abstract nonsense.
Unless you are using a strictly FP language, you are always basically using objects.
And all the stuff like factories and everything exist in FP as well, it's pretty short sighted to say otherwise. These are patterns that may or may not be useful in a given case. Sometimes a language feature can replace them (e.g. pattern matching ~ visitor pattern, but not even this is a full match see closed vs open hierarchy), but in most cases you just call them something else/don't have that problem because you are not writing that big of a software.
Bit of an extreme position, no? Languages without OO tend to end up reinventing it. Like the Linux kernel style of "big C structure with function pointers": that's just a vtable which you have to maintain by hand. Or, god help you, trying to do COM in C.
What's a good codebase that is very large but without either OO or pseudo-OO?
I totally agree one ought not use a non-OOP language for OOP. Right tools for the job and all that.
I work on large (but private, so I cannot share, sadly) FP-style codebases. The code style is stateless functions grouped in modules that operate on data-only structs in a factory line manner. Typed boundaries for correctness, short and maintainable functions for clarity. No member functions, so no vtables.
I've never seen such code need or use OOP design patterns. I'm just very gently pushing back against the idea all code devolves into OOP spaghetti in due course. It doesn't! There are better ways. :)
Lack of virtual threads was its biggest remaining problem because this made the common ways of doing cooperative multitasking very ugly. Go's big thing was having that from the start. Maybe now that Java has it too, it's set?
Though JS will still have the least boilerplate because of the way it handles types.
IMO, Kotlin coroutines are better of Go's goroutines, although they are a little different beasts to compare honestly (apples and oranges). Go inits goroutines on stack, but min size is 4KiB, so it's not trivial to grow them. Also you need to watch over and destruct goroutines manually to prevent memory leaks (using
var wg = sync.WaitGroup
defer wg.wait()
wg.Add(1)
go func() {
defer wg.Done()
}
)
And create a separate channel to return errors from a goroutine. Definitely more work.
Kotlin coroutines don't really exist. They're a (very neat) programming trick to support coroutine-like behavior on the JVM which doesn't support coroutines. If you look at the bytecode it produces, it honestly is a mess. And it colours your functions too: now you have be ever careful that if your function is running in a coroutine, there are certain things you should absolutely avoid doing in that function, or any function called by that function (like spinning the CPU on loop without yielding). In Go, you don't have to worry about any of this because the concurrency is built-in from the start.
Also I don't understand "it's not trivial to grow them". It is trivial to grow them, and that's why Go went this way. Maybe only 0.1% or fewer of use-cases will ever find any issues with the resizing stack (in fact probably the majority of uses are fine within the default starting stack size).
> Kotlin coroutines don't really exist. They're a (very neat) programming trick to support coroutine-like behavior on the JVM
Well, guess how coroutines are implemented in Rust/C++/everywhere else!
Nonetheless, I do think that java virtual threads are superior for the vast majority of use cases and they are a good default to reach for for "async" like code.
I think there is something to say for compiling to native code, having binaries in the ~25 MiB range, being able to run in distroless containers, being able to run a web application with less than 100MiB of memory and startup times measured in milliseconds rather than seconds (sometimes dozens of seconds).
Don't get me wrong, I like Java and don't very much like the Go language. But Java has a lot to improve upon still.
Small java programs start up well in the milliseconds.
I don't really think it's fair to compare some old jboss monstrosity doing the job of a whole kubernetes cluster to a dumb hello world server written in go.
Sure, java startup time is and will probably always be worse than putting everything into a single binary - but it is way overblown in many discussions. I have a bunch of Quarkus services on my home server and they start up immediately.
With Quarkus (and other new frameworks) you can have webapps with less than 100MiB. Startup times in a couple of miliseconds. CLI apps, with limited number of third party libraries are under 40-50MiBs.
I think astronomers could measure the age of the universe in nano-Valhallas. Every year, it feels 50% closer to completion...
In all seriousness I'm happy with what Mr. Goetz and the team have done. Sealed interfaces (java 17) + exhaustive switch statements (java 21) means we now have union types in java! And instead of jumping on the async/await bandwagon we now have a more general solution that doesn't lead to API duplication (virtual threads). But Valhalla has been a veeery long time coming.
'Tis true. At the same time, Project Valhalla will be the most significant change to the JVM in a very long time, and probably its best chance to stay relevant in the future.
If we ignore the fact that value types likely won’t ship before we have flying cars, Java has evolved greatly. I really like how they’ve solved concurrency, but I dislike how they’ve handled modules but this a minor issue.
The main problem with Java has always been its build tools. They’ve consistently been bad and continue to be. Even today, creating a bundled application with a stripped down JDK with jlink and jpackage is incredibly painful. You’ll need extensive knowledge of the Java CLI, modules, build tool plugins, or tools like Mill which simplify using jlink and jpackage, but even then it remains complex and frequently fails. In reality it should be as simple as something like "java package". Even these days, I frequently see Java developers presenting their desktop apps on Reddit and if you look at how they deploy them, it's often a fat JAR because they struggle to use jlink and jpackage effectively. Ironically, even generateing a fat JAR can be challenging.
As someone who has spent over two decades developing desktop applications including witnessing the shift to horrendous Electron firsthand I can tell you that this was a primary reason Java basically vanished from being so prevalent on desktops. Inexperienced developers often struggled to deploy even simple Java applications, grappling with either runtime incompatibilities (Ironically, developers are somewhat reintroducing the same problem with WebView-based applications) or having to tell their users how to launch a Java app. While some claim desktop apps are dead – which is nonsense – the same applies to CLI applications. CLI apps remain prevalent, primarily written in native languages or Golang, sometimes even Node or one of its derivatives. Rarely Java for the reasons I just mentioned and don't get me started with Graal Native. If someone decides to write a simple trivial CLI app in Golang, they'll simply build it with a single command and be done with it. With Graal Native, you'll have to go through using the tracing agent, and if you're lucky you'll have a fat native executable after minutes of compile time. Forget Graal for a minute though. Java would already go a long way if bundling your application with a stripped down JDK (jlink) was as easy as typing in a single command without having to deal with complicated Maven or Gradle plugins.
TIL Mill, I've been in build hell trying to package a javafx GUI gradle project that depends on a non-module-ified lib (usb4java, long story, no I can't use anything else). Beryx/badass failed entirely, was able to get something working with Gradle doing jlink and manual CLI jpackage ...
But tbh the whole experience makes me distrust the Java ecosystem if you're supporting anything that is slightly out of the community's view or priorities. Even JavaFX shows very patchy support for certain very standard UI concepts, and the situation with packaging is bad as you say.
Anyway, is mill worth switching away from Gradle? (Does mill integrate at all with idea?)
Mill does work with idea (via the build server protocol), and the ideas behind it are very sound (a build tool is basically a function calling other functions - on which they depend. You just want to parallelize their running and cache their results.
But it does have a learning curve and you may sometimes end up having strange error messages. (As an implementation, it's basically Scala macros turning normal looking scala functions into a static task graph). It is getting better and better support for mainstream java build setups, and it's possibly the best tool for something very custom. In between the two extremes, you may or may not have a better time with Gradle/Maven.
I feel like Gradle is only relevant for Android. All other projects are fine with Maven (and I like a lot that Maven doesn't allow to code in the build config, any complex logic should be extracted to a custom build plugin, using real code. I just have PTSD after some build.gradle monstrosities).
It's just that Maven doesn't have a good core abstraction and it is not a reliable build system. Like even with base plugins, let alone with additional ones you can't be sure that a build actually picked up every change, you often have to do a double take and do a clean install instead to get some stale files cleared. This should never happen in a build tool and every other feature is secondary to this error.
That's why I defaulted to Gradle, which has its own idiocities (like tending to break the syntax on every second major version, but it's much better with the kotlin DSL), which at least 100% sound.
For more experimental/hobby projects I choose mill though.
Glad to see this being removed. Java plugins especially on Linux were awful and required by tons of corporate stuff. Anyone remeber IcedTea Web? A functional and opensource Java plugin and Java Webstart implementation?
Note that the the Java plugin and webstart was removed a long time ago.
I personally regret that the API was removed as it's a few classes and they are still used. Just search JApplet on Github. It's also possible to run applets in the modern browsers with WASM or in Java IDE's as plugin.
I made several Webstart corporate apps back in the day! The infrastructure was pretty neat, when it worked. And it was a whole lot better than JS back then, still in the IE6 times.
I was pretty surprised when I learned recently that the Java alternative for green threads doesn't use colored functions. It put Java in a higher place in my perception.
It doesn't completely solve function coloring though. Causing carrier threads to get pinned is still not good, similarly as calling blocking function from async function is not good in colored systems.
Any time you have a barrier between one function being able to call another. The original article on this called them red functions and green functions. A green function can call a red function but a red function can't call a green function.
In terms of async, it's when you have to have a function with "async" attached to it and making it so that only other async functions can call async functions.
It ends up creating a weird circumstance where you can end up with a lot of duplicated APIs, particularly in libraries, because you are providing both async and non-async versions of functions.
The coloring is a property of concurrency safety and whether the language enforces it.
For instance, if you resolve a future in the wrong context you'll still have problems - the coloring is just a compile time error that you are doing things wrong, rather than a runtime deadlock.
The term comes from an old blog post [0] about different kinds of effect systems. Every function has a color, and every colored function can only call functions that are compatible with it, usually of the same color. The net result is that you end up either duplicating a lot of your common code so you have compatible interfaces for all the different colors (let's call that "separate but equal" if we're feeling spicy), or you end up shoving round pegs into the square holes of your dominant function color.
The terminology is used to talk about languages that have async and sync functions where you declare (or color) the function as either async or sync.
In these languages it's pretty common for the language to enforce a constraint that async functions can only call other async functions. Javascript / Typescript, Python are popular examples of languages with colored functions.
No, it refers to a function that has constraints on how it can be called and composed. A classic example is functions tagged `async` in languages like Javascript or Rust.
(Technically, that's the symptom - the underlying cause is that it's a function that involves some effect, like asynchronicity, or, in some functional languages, IO.)
"green threads" is generally how I see these systems identify as "non-colored but with async-like performance" fwiw. or "fibers". otherwise it's "async" or "coroutines".
There are different types of coroutines. The C++ type are sometimes called "stackless coroutines". With stackless coroutines you can't yield from a nested function call. Stackless coroutines are basically generators where you can pass arguments through resume, and async/await is effectively a form of stackless coroutines with yield/resume semantics that aren't fully generalized as coroutines, but oriented toward some bespoke notion of concurrency rather than as an abstract control flow operator.
"Stackful coroutines" allow yielding from any arbitrary point. They're basically fibers, except with the explicit control transfer and value passing yield and resume operators; there's no hidden or implicit control transfer like with green threads. Though, some people would argue allowing any function to yield without announcing this in their type signature is tantamount to hidden control transfer. Personally, I don't see how that's different than allowing any function to call other functions, or to loop, but in any event languages are free to layer on additional typing constraints--constraints that can be tailored to the desired typing semantics, rather than dictated by implementation details.
Stackless coroutines are typically implemented as a special kind of function whose state is allocated and instantiated by the caller. In contrast, stackful coroutines are typically implemented by reifying the stack, similar to threads. The "stack" may or not be the same as the system's ABI stack.
In stackful coroutines, unless there are additional typing constraints imposed by the language for hygiene reasons, any function can typically be called as a coroutine or use yield and resume. There's no need to compile functions into special alternative forms as call frame management works the same whether invoked from a coroutine context or not.
What alternative would they be referring to? Green threads were only (re-)introduced to Java in version 21 in 2023.
I think what they're trying to say is that Java's green thread implementation has special support for async I/O. Threads that block on I/O aren't polled for completion by the runtime, instead they use OS async features under the hood.
This allows Java's green threads to compete performance-wise with async/await solutions, but with cleaner code that doesn't need colored functions.
In older green thread implementations in other languages, I/O can actually cause significant CPU overhead due to polling threads that are blocked by I/O requests.
I have been using Java since version 1.4. Both the language and its ecosystem have come a long way since then. I endured the height of the EJB phase. I adopted Spring when version 1.2 was released. I spent hours fighting with IDEs to run OSGi bundles. I hated building UIs with Swing/AWT, many of which are still in use today and are gradually being replaced by lovely JavaFX. When I look at code I wrote around 12 years ago, I'm amazed at how much I've matured too.
> I hated building UIs with Swing/AWT, many of which are still in use today and are gradually being replaced by lovely JavaFX.
Dude JFX yielded what was called RIAs to JavaScript like almost 15 years ago. Of the three major GUI toolkits Swing, JavaFX, and SWT it was Swing that gained HighDPI support first (10 years ago), and continues to be the base for kick-as IntelliJ IDEA and other Jetbrains IDEs.
Swing was simpler in some ways than JavaFX. I still remember JavaFX treeview taking 3 Generics and I was unable to figure out what one of them is for from the docs. Had to go on Stackoverflow, where someone said it basically didn't matter. But JavaFX looked great at the time.
As someone who has been out of the Java world for many years, but recently forced back into it due to Android dev requirements, Post lawsuit, what is the relationship between Android (Google) and Java now? When can we expect 26 on Android? On that note, why is Android always so far behind? Is it because Kotlin is primary or is it deeper? Did the lawsuit play a role?
Android has their own runtime (creatively named as Android runtime), which does not run java byte code, but their own binary format. JVM class files can be compiled to that format, but the support for that always lags behind OpenJDK java versions.
Part of the reason kotlin became the de facto language on the platform was that they supported only terribly old Java at the time, that didn't even have lambdas even though it was already out.
The problem is that most of the Java libraries want to follow the desktop/server, aka the OpenJDK scene, but that would make them incompatible with Android so there was/is some incentives to bump up the version they support.
The new (ish?) Android UI toolkit is only useable from Kotlin and is implemented fully as a compiler plugin. Google has been clear that Kotlin is the Android language now and that's where new features are going.
I do really need to give flutter a try. My only reason I haven't yet is that I have no desire to learn Dart. How do you (or anyone) like Dart compared to Java or Kotlin?
The new concepts for me were using immutable classes with the keyword "final", and the whole concept of state management in mobile apps because I've mainly done backend.
I've only used kotlin in the android files for flutter but nothing else.
I'm also not totally objective on that because my Java experience is from a long long time ago, my general feeling is that flutter is less bloated than java.
And I don't want to start a culture war on this, because we all know turbo Pascal is the best.
I haven't read a Java manual since the time of Java 8. Do you have any books or other resources you could recommend to catch up with all that has changed in these years?
All the changes look great. But I don't know how I feel about the syntax. A lot of things that very well could be first-class just aren't. Instead of a `lazy` keyword, we get `LazyConstant<T>`.
I'm sure there's reasons as to why. I just don't know them.
It‘s easier to evolve library code. If Java would ever infer type of constants from initializer (makes more sense than a new keyword), it could look nice and powerful:
Once introduced, keywords and Java syntax is nearly impossible to change or to remove. If it's possible to get the job done using a class, perhaps with some JVM magic, it's not wise to whip out new syntax.
Seeing as we're having a $LANG war, after 15 years in JVM land, I moved to a Python / Go shop, and fuck I miss Java.
Not so much the language (although modern Java is pretty slick), but the stuff surrounding it.
* No typosquatting issues because every package has a group id verified by real humans and DNS TXT records.
* JMX as a standardized mechanism of exposing ways to interact with running code / expose metrics. (Even if you have to deal with the stupid ass protocol where you have to connect using a DNS identity the JMX server recognizes)
* Logging libraries that give people running the code control over what gets logged and how, not the developers (looking at you Golang, wtf is with your logging approach where devs have to explicitly consider the fact that you might want to run logging at DEBUG and code it into your start up args?)
* The ability (via JMX) to set, at runtime, one particular logger in one class or file to a desired logging level without restarting the application.
* The performance of the JVM.
* The vast FOSS ecosystem.
* Not having to fight C build chains for that one dependency that's using CGo or a Python wrapper around a C lib that no wheel supports for your given tuple of Python version, OS, and architecture.
Honestly, as someone who is a self-taught developer who taught himself in Python, I thought I was coming home to my first love.
Turns out, I really hate the horrible things you can do in Python - looking at you Django, don't be so dynamic your brains fall out - and really dislike the experience of trying to run a Go service compared to a JVM service.
Java and its ecosystem is just good at getting shit done in a predictable manner at both the dev level and ops level.
> * No typosquatting issues because every package has a group id verified by real humans and DNS TXT records.
While I think this is a huge boon, have you ever published a package on the Maven Central repository? I must confess I haven't in a few years now, but when I did until ~3 years ago it was a major pain in the ass. And every release again.
I think there's something to say about Go's model where the package is just in some Git hosting and a release is just creating a tag. As a package maintainer, this is just pure bliss compared to the Maven thing.
> and really dislike the experience of trying to run a Go service compared to a JVM service.
What are you running into specifically? I have the complete opposite experience. With Go, 1 small binary comes out that I can run anywhere (and put into a distroless container), whereas with Java I have to find a way to somehow run a full JVM (most often with (large parts of) an OS too).
Perhaps you're alluding to the things you can do with JMX, but I have never really seen much benefit in that. I found it trivial to add similar functionalities with internal HTTP endpoints easily. But since I don't have much experience in this particular area, probably I'm missing something.
> While I think this is a huge boon, have you ever published a package on the Maven Central repository? I must confess I haven't in a few years now, but when I did until ~3 years ago it was a major pain in the ass. And every release again.
I’m really surprised to read this. It is well-documented process. I regularly publish something there, never had problems. Why was it different for you?
Yeah, publishing a package is a PITA for the precise reasons of maintaining trust in, and the quality of the packages.
That's why you need documentation to publish to Maven central, that's why your package needs to specify its license, GPG checksum etc.
Yep, it's a lot harder than publishing to Pypi or Cargo, but I'm now firmly of the opinion that it's good that it is. The gates between you and publishing a package are there for deliberate reasons.
> Perhaps you're alluding to the things you can do with JMX
Yep, specifically things like "set the logger org.foo.package.Bla to DEBUG while the app is running", without restarting and without having to add an internal HTTP endpoint to be able to accomplish that. It's just there for free, every JVM logging library and metrics library exposes itself via JMX for that same reason - ease of observability, without restarts, without custom code.
E.g., I can access Kafka client metrics via JMX anytime I like. JConsole will even give me pretty graphs.
If I want them in Prometheus, I run the app with a Java agent that takes those MBean metrics and exports them in Prometheus format on an HTTPS endpoint.
I understand you can accomplish much the same with some internal HTTP endpoints, but that presumes they exist.
If you need them, but that microservice hasn't deliberately exposed them, you need to change the code, and then make a new release, which slows down your ability to diagnose what's going on right now.
In Java, every observability library exposes itself via JMX, all you had to do as a sysop was ensure that the JMX port was open.
Also, the ability to easily observe the metrics of the VM itself via JMX so I can see what's going on with GC in a running app without having to explicitly expose that.
If you suspect a memory leak, or something that should be GC-able isn't, or that there's far too many object allocations occurring that's smashing the first gen portion of the heap and causing excessive GC pauses, the instrumentation to investigate it as your app runs is right there, it's baked into the JVM.
That's why I miss it - the JVM was built to be instrumented and observed by the people running it.
I really wish Golang and everyone else would emulate the Java approach to observable metrics as well as the Java approach to logging and packaging.
There's no shame in stealing the good ideas Java had, but no-one seems to, to my frustration.
Some of the standard library stuff could be usable from Clojure and other languages. The jvm level optimizations (garbage collection) should benefit all jvm languages. The language changes are mostly not that relevant unless you program directly in Java.
I use Kotlin myself (after doing Java since 1995). Most of the overview here reads like they are adding a lot of stuff that Kotlin has had for many years. Structured concurrency, lazy stuff, etc. You can argue about which language does it better/nicer/etc. but that debate is a bit boring to me. But good for Java developers that they are getting some obviously useful things that so far they never had. Progress is nice. Better late than never.
Java improvements usually have a runtime component, so no, kotlin simply couldn't have had Lazy no matter what. It was just syntactic sugar for a getter.
That's what most modern programming languages provide. Syntax matters. Kotlin offers a lot of syntactic sugar for things that are a bit verbose in Java.
The new structured concurrency stuff in Java is actually a great example of that. More or less does the same thing, Kotlin manages to do it with a nice Kotlin DSL. Java does it with a lot of builders and function chaining. Which is a lot less readable.
In the end, Java caught up and you can now use this for more complex concurrent/parallel code (both should be possible with this, like it is with co-routines in Kotlin). Which is a good thing.
Didn't mean to say that syntactic sugar is bad. But when Java touches a language feature they prefer doing it only when absolutely necessary and even then having the biggest part be in the runtime if possible. E.g. in the lazy case, it's backed by runtime optimizations, they are treated as proper constants. A fancy getter over a lambda is not the same thing, and that's all syntactic sugar in this case would give you.
Sometimes, yes. E.g. if the value types stuff ever gets implemented, that will be very useful for other JVM languages. OTOH some changes are purely syntax sugar in Java itself (e.g. allowing multiline string literals) and those of course don't affect any other JVM language.
I'm pretty sure all of Clojure runs on Java 8, so if you use some new feature I'm guessing you need to provide a fallback - but you're also going to be running on Javascript and other platforms, so that's par for the course
Still a lot, but in absolute terms the majority of Java applications are 8+ for 4-5 years now, according to Oracle's statistics - so they are a minority. It's just that there are so many java projects that it is still a huge number.
When it was about the 7th incubator iteration, I got curious so I read the actual JEP history, and it had this informative tidbit, also included in the latest release:
"The Vector API will incubate until necessary features of Project Valhalla become available as preview features. At that time, we will adapt the Vector API and its implementation to use them and then promote the Vector API from incubation to preview."
Project Valhalla has been "in progress" for at least a decade now (Wikipedia say 2014). So who knows when we'll actually see a Vector API in preview.
They made the problem complexity of Valhalla ~10,000x harder by very strict backward compatibility needs. Project Valhalla can take many human generations and multi-billion man years to finish as a consequence.
Google basically played a J++ with Android Java, with Kotlin as their .NET/C#.
At least they are forced to partially update Android Java, now Java 17 subset, so that Kotlin can keep up with was is mostly deployed at Maven Central.
Pretty sure they did a J# ;). But I agree that Kotlin is their C#.
The JDK and JVM has advanced so fast while android has been lagging. It's pretty frustrating, especially because google has been so slow to pull in changes from later java versions.
A part of me wishes that android would just dump their hokey dalvik, ART, and other BS and just use the OpenJDK or a fork of the OpenJDK with whatever special sauce they need. A lot of the project Leyden stuff lends itself nicely to maybe someday being able to run real java on android.
Edit: Apparently android is forking OpenJDK, since Android 7.
Correct, and J# was a brief transition language to help migrate Visual J++ applications onto the .Net SDK. J++ -> J# -> C# was the evolution.
I say J# is a more apt comparison because like Microsoft's Java, android has a substantial set of APIs that aren't part of the JDK standard. Working on Java vs Anrdoid is practically like working with the JDK vs .Net.
It isn't, check Gerrit commit history, they only take bits and pieces, plus ART doesn't do all bytecode equivalents. Some JVM bytecode don't have counterparts in Dex, rather get desugared into multiple instructions.
J# was the transition product to port J++ into .NET, I am quite sure.
Not only I was there on those years, my employer was a MSFT partner that got to test .NET before it was announced to the world, so that we could have our products as part of the announcement event in Portugal.
OpenJDK is cherry picked, Google only picks pieces of it, rather than full compatibility.
No idea what you are talking about. Google internally has a massive amount of code based on JDK 21, and the (amazing and completely transparent move) to JDK 25 is nearly complete.
That's the full OpenJDK @ Google, and it has been for a very long time.
No, they didn't. Google happily used regular Java until Oracle played Oracle. Then Google stopped updating the supported Java language version and started diversifying away from Java.
They definitely did not, it was Android Java from day one, and Oracle should have crushed them like Sun did to Microsoft, unfortunately Google was the geek darling of do not evil, thus they got a pass from fanboys.
Oracle's Java Mobile Edition could've crushed Android. No one stopped them.
> Google was the geek darling of do not evil, thus they got a pass from fanboys.
Oracle's case against Google went all the way up to Supreme Court of US. Oracle did not win anything substantial in courts against Google is not fanboys' doing.
Android was not 100% compatible with Java, but mostly because it had a specialized environment. It did not support things like dynamic bytecode generation, but it faithfully reproduced pretty much everything else that made sense.
And yeah, it would have been so much better with Oracle(tm)(r)(c)(fuckyou) running Android with Pure Java(tm)(r)(c)(screwyou) instead. Now with EJB5 and more XML!
You might be too young to remember, but SunOracle essentially abandoned the Java language development for more than a decade, until Kotlin provided a very much needed magic kick.
Oh, and if you think _Google_ is bad for splitting the Java ecosystem, let me introduce you to J2ME and JavaCard.
I think Java became popular because of Sun. My experience with Java-based apps is bad. Laggy, resource-heavy, IDE bound, and it causes premature hardware performance degradation.
Modern Java is pretty succinct and expressive and I enjoy working with it. Like any long-lived project, Java has its quirks and baggage but you can let go of that baggage if you want. The ecosystem is evolving nicely with new features and it is quite pleasant to work with these days. I’m looking forward to migrate apps at work to 26.
the people that work on Java & the JVM are very smart.
it has become a best of breed language - hell its better than Go for industry purposes.
the drawback with Java will always be the CULTURE - (maybe someone can insert a quote of how in physics progress is only made, when old physicist die - I don't wanna be morbid ) but with Java same that's when the culture will change.
All those people using typescript (could be using Java - but the culture doesn't want them and consider them heretics for not embracing religion of OOP and FactoryFactory)
> for not embracing religion of OOP and FactoryFactory
Not the case today. Of course, crappy code (or questionable patterns) can be found in all languages, and java community had made some innovations in the area early on, but today we have a different picture.
FactoryFactory has gone mostly extinct, the most likely place to see it is “dailywtf.com”.
We now know that we prefer composition over inheritance, we have stream api - language and community evolved, old patterns are not neccessary anymore to solve same/similar problems.
Sample of one - junit (testing lib) source code, from quick glance it seems more procedural than dogmatic OOP: https://github.com/junit-team/junit-framework/blob/main/juni...
> We now know that we prefer composition over inheritance
When people say "composition over inheritance" in Java discussions, they usually mean the trivial modeling rule: prefer has-a over is-a.
But that’s not what composition is really about.
The deeper idea is interface composition -- building types by composing multiple behavioral contracts behind a single cohesive surface.
Java provides inheritance and interfaces, but it doesn’t provide first-class delegation or traits. So most developers never really practice interface composition. They either subclass, or they wire objects together and expose the wiring.
The slogan survived. The concept mostly didn’t.
The manifold project, for example, experiments with language-level delegation to make interface composition practical with Java.
https://github.com/manifold-systems/manifold/blob/master/man...
> Java provides inheritance and interfaces, but it doesn’t provide first-class delegation or traits.
I'm not sure I am missing first class delegation much (not a lot of UI projects in Java these days).
But interfaces with default (and static) method implementations are actually quite usable as traits / mixins. Since Java 8 IIRC.
You can also pass around functions / lambdas (coincidentally also since Java 8) to compose functionality together. A bit harder to follow and/or understand, but another perfectly legitimate and very powerful tool nevertheless.
Well, what mainstream language has better tools for composition?
Rust with traits and Swift with protocols
So just type classes?
How does a type class help with composition? They do help with the expression problem (adding support for an "interface" after definition), and via parametric polymorphism they might give you a bit with regards to composing two traits.. but you do also have generics in Java, even if not as good as type classes.
So anyways, I don't see as big of a change here. But there was a Brian Goetz mail/presentation somewhere where he talked about adding "basically type classes" to Java? But unfortunately I couldn't find it for you now.
kotlin
Kotlin's "delegation" feature isn't true delegation, it's just call forwarding, which is better than nothing, but it falls down pretty quickly as an alternative to implementation inheritance.
The manifold project provides true delegation[1] for Java.
1. https://github.com/manifold-systems/manifold/blob/master/man...
> FactoryFactory has gone mostly extinct
it really depends on your project, and what framework(s) and libraries you choose to use.
Java still has a tonne of legacy projects using old(er) frameworks that rely on such patterns - spring has some old versions which is like that, and i am certain plenty of java projects are retaining those old versions due to lack of desire to upgrade.
If you're starting a greenfield development in java, you surely would not befall into that factoryfactory pattern (unless you're just copy/pasting old projects around...). But i imagine there's way fewer greenfield projects compared to older projects requiring maintenance.
It's still going to be hard to overcome the stigma of ex-Java developers coming into other languages and bringing their overly complex ideas with them. But I am happy to hear Java itself is evolving and I hope that limits the downstream effects of it being one of the most popular language a lot of devs start on.
It's getting better, it doesn't all have to be Spring Boot and JBoss.
There is quarkus, helidon and micronaut for slimmer more modern backend frameworks. jbang for scripting (think uvx, bunx), Tambo UI (https://tamboui.dev/) for terminal UIs, and more.
Along with all the new Java features that help you write much simpler code - eg. virtual threads, structured concurrency, stream gatherers, and performance / resource improvements.
It's not all there yet, but I think the next few years things will come together nicely (however a better build system is sorely needed - one of the things that Go / Rust did right).
Not sure if I agree about the Go build system. Causes me endless issues at work - and my workmates, going by the number of complaints
I'd like to mention the web framework I'm using these days, Jooby:
https://jooby.io/
I've found it quite satisfying compared to the other "new" ones.
As for the original topic, I just want to echo what others have said, and say that I am happiest in Java when writing it as if it were Golang code. That an the first-class runtime and performance and deep ecosystem make it a great choice in 2026.
There's also Javalin for oneshot java projects where you write your webserver like you'd write express.js
Quarkus is better, but isn’t that amazing IMO.
It’s still very much an annotation festival in the code, making the framework quite lengthy to learn for newcomers (gotta learn Java and the whole quarkus annotation DSL with it).
Go is verbose, but it is much more explicit and only uses standard language things instead of a whole annotation DSL.
Helidon SE (https://helidon.io/#se) or Javalin (https://javalin.io/) would be more in that vein - straight-forward modern Java, super fast.
In my opinion Helidon is the most refreshing of these frameworks. It supports virtual threads from the ground up and comes with clean, function, mostly annotation free APIs. It really looks like a Java framework should look today.
There are non-DSL frameworks in Java. It's just that arguably the benefits of a DSL outweigh learning them.
Putting an annotation on a method is much easier than registering this method at n places in ordinary code, which could look any number of ways. If you move to a new project, in the first case can just immediately jump into framework-related stuff, while in the second all this logic has to be untangled first. And let's be honest, Spring/Quarkus probably got their abstraction right after n iterations, which is not necessarily true of a random team.
If someone reads this and wonders what JBoss is, the contemporary variety is called WildFly and it is actually rather easy to install and play around with.
https://www.wildfly.org/
I think this is an often overlooked solution to some of the problems we nowadays tend to approach the clown for.
As for build systems, Maven is old and cranky but if something else replaces it, it will probably be quite similar anyway.
As you’re familiar with the JBoss space, why would someone use an enterprise container over a simple HTTP server (Tomcat, Jetty, etc)?
Currently I’m trying to externalize as much as possible to the service mesh. I want teams to stand up a basic unencrypted HTTP server that accepts the company headers and just works with as minimal of a runtime as possible.
I wouldn't use application servers today, but they were solving many of the same issues as whole kubernetes clusters do, decades ago.
The Java (now Jakarta) EE standard on top is a good base for third party implementations to "speak a common language", e.g. it's not that hard to move between Quarkus/spring/micronaut etc, even if not all support the actual standard.
Yep, I'm using JBoss as a catch-all for older "big-iron" style Application Servers - modern Jakarta EE (10 onwards) is much more slimmed down, and a solid option.
unsure re Maven, 4.0.0 has been around the corner for years, but I think there is space for a modern alternative that is JPMS first, supports semantic versioning (i.e. tilde/carat notation) with lockfiles, and doesn't require a bunch of plugins out of the box for common use-cases. Maybe Mill (https://mill-build.org) - i've yet to try it.
Mill looks kind of nice on the surface but I haven't seen it in action in any serious project. I suspect the flexible DSL might come with a maintenance burden.
XML is nice, if your pom.xml is massive, just suck it in through JAXB and program against it, perhaps render it to a web page. XSLT can also be helpful. We're not supposed to look at XML as plain text.
> As for build systems, Maven is old and cranky but if something else replaces it, it will probably be quite similar anyway.
Bazel is the most obvious contender and very different from Maven in almost every possible way.
Not really, no. It is similar but worse than Maven in that it requires quite a bit of time investment to configure, and shares the drawback of Gradle that it is configured in a programming language instead of a configuration language.
Switching out Maven for a larger maintenance burden might be reasonable in a large organisation that is swimming in competent employees, but most do not.
As for obvious contender, I'd say that would be Gradle, which is harder to get someone started with than Maven and due to the DSL allows you to invent weirder footguns.
Did everyone just agree to forget about Gradle? It was everywhere not too long ago. I think I even prefer it to Maven, in a choice between a rock and a hard place type of way.
I don't think so, but the pain points have become more widely known and taken the edge off the hype.
JBoss was great back in the day. I remember when there was a JRuby port of it called Torquebox that I loved.
Eventually though, I found Elixir and it gave me everything I was looking for from that stack.
Yeah, same, but Elixir gigs aren't as common as Java gigs. However, if one ends up in a Java role, chances are that Elixir would be a good porting target for the systems since it typically can replicate the architecture but with less fuss and has pretty good support for interfacing with Java.
A friend and former colleague was agog about Quarkus and it does look pretty compelling.
I never want to read another Bean or log4j config ever again.
Didn't they all switch to convention over configuration and dependency injection so now your configuration is your source code?
Some people did but that's actually worse. Your configuration comes magically out of nowhere and when it breaks you can't fix it.
Nobody ever wanted to wire up RPC endpoints, in the form of Enterprise JavaBeans(tm), using XML files. That is one for the history books of ridiculous technology.
XML files are bad. Invisible magic is worse. The sensible way to wire up a bunch of RPC endpoints is, like the sensible way to do most things, plain old code.
Having used micronaut for a few years now, I hate it.
Maybe it's innate to trying to use a a fully fledged server-style framework in a serverless context, but I don't think it's suitable. In fact I think the whole idea ("Hey, let's bludgeon spring-like metaphors into an entirely new setting") was a poor one.
Java itself I've enjoyed more and more over time as the language has evolved into something much more expressive, and without all the enterprise crap. My hope is that one day frameworks like Micronaut will end up discarded too.
It was a while back (when I was a worse programmer) I found both Micronaut and Quarkus dev experience more palatable than spring.
what did you dislike? Pervasive DI? Annotations? configuration mess?
Never done much Spring, so I don't have a lot to compare to. But ...
I'm not a massive fan of using annotations in concept, because they obfuscate what's taking place. Unlike in (say) Python, where annotations are effectively functions wrapping the function they annotate, in java they're more akin to a customisable preprocessor. Obviously I do use them, liberally, because that's the way things are done, but I'm not a big fan. And using any modern framework relies on these a lot.
Micronaut gripes -
1. It works great until it doesn't, and you have a special case, and then you have to dig into source to figure out what on earth is going on.
2. Keeping up with latest isn't always easy, micronaut 3->4 was a huge effort.
3. For all it's called micronaut, the produced packages are pretty huge.
Serverless-specific gripes -
1. What I'm receiving isn't really an http message over a socket. It's an AWS gateway event with everything already read and packaged up. So there's no reason that (for instance) I shouldn't access the message body in a request filter, because I don't give a crap about the jetty server-loop being non-blocking.
2. Startup time is terrible. And when I managed to get a native compiled version to actually run, it got worse. A lot of this seems to be down to hibernate, but there's a big gap between startup and any logging from the framework at all. We've tried a bunch of stuff to remediate, so far with little success.
In general I think that serverless is such a different paradigm from a long-running server that approaching it from the point of view of "how can we make this the same so developers who've never thought outside of the spring-like box can still be productive?" was wrong from the outset.
> Unlike in (say) Python, where annotations are effectively functions wrapping the function they annotate, in java they're more akin to a customisable preprocessor.
I find that Python decorators can do as much magic as an annotation processor - due to the dynamism of Python. Annotation processors, in most cases, produce a new class based on annotations on existing class / interface. The injection of that class is done by the DI container (unless it's a standalone annotation processor like mapstruct).
> And using any modern framework relies on these a lot.
To be fair to language designers, it's hard to avoid code generators. And they're a compelling thing compared to building proxy objects / DI / decorator / dataclass etc.. kind of functionality in language and getting it wrong.
> ... then you have to dig into source to figure out
Agree. It's not a "boring technology" yet.
> For all it's called micronaut, the produced packages are pretty huge.
How huge? And jlink or graal vm? Just curious.
> A lot of this seems to be down to hibernate,
With micronaut atleast, I remember using Micronaut Data JDBC. Anything is better than hibernate.
> In general I think that serverless is such a different paradigm from a long-running server.
Agreed.
> a better build system is sorely needed - one of the things that Go / Rust did right
Honestly there are only two reasons I wouldn't pick up Java for personal projects, difficult to build single executable (Graal is still very un-ergonomic), ridiculous build systems.
I can kind of live with former, but Gradle is so very extraordinarily terrible that I don't know where to begin. Problem is, it solves some real problems (in extremely bad way) that people keep using it.
I long of a cargo-style revolution in Java world. (No, the newly popped up alternatives haven't really cut it so far)
After ~13 years of working with C#, I moved to Kotlin. It's such a beautiful language. When I have to read docs for a Java lib I realize why I like Kotlin.
I want to say culture around Java doesn't have to change, new culture is growing around succinctness (if not simplicity) of Kotlin, and it gets most of the benefits of Java ecosystem.
I also like Kotlin. The readability is awesome. ;)
I get the snark, but also - there is this "ideal Java code style" that most experienced devs tend towards. Unfortunately I don't see anything like that for Kotlin (yet?), and there are a bunch of patterns that I really dislike. I sometimes feel people just toy around, like "wow I can make this into an extension method, how cool" and leave that as the code.
In general, I really dislike extension methods, especially when paired with tiny objects with barely any functionality to begin with. Like people build a mental model of what a thing is based on how can it be used - but if you leave that empty and put every behavior at different files in the form of extension methods you make this understanding very hard to build up.
Add to it that it removes polymorphism and often actually hinders readability.. so my point is, having more ways to write code is not necessarily a positive.
I must say I prefer C# over Java. They're pretty similar in a lot of ways, but LINQ is much nicer to use than the Java streaming equivalents. And there are some odd warts like Java lacking unsigned types.
I wonder if at we are standing looking at the smoking field of programming languages created over the last 50 years and gazing at the final survivors, of which Java is definitely one.
Why would anyone create a new language now? The existing ones are "good enough", and without a body of examples for LLMs to train on, a new language has little chance getting traction.
I learned IBM /360 assembler when I started in computers a long time ago. I haven't seen a line of assembler in many decades, but I'm sure it's a viable language still if you need it.
Java has won (alongside many other winners of course), now the AI drawbridge is being raised to stop new entrants and my pick is that Java will still be here in 50 years time, it's just no humans will be creating it.
> Why would anyone create a new language now?
I'm writing my own programming language right now... which is for an intensely narrow use case, I'm building a testbed for comparing floating-point implementations without messy language semantics getting in the way.
There's lots of reasons to write your own programming language, especially since if you don't care about it actually displacing existing languages.
Most of my 20 years of experience is Java. Now 3 years into a new job mostly using Python to build microservices. I feel much more productive using Python (plus uv, ruff and mypy for fast repeatable package management, linting and type checking). I see Python having a trajectory to keep improving and gaining more adoption - eg Python keeps growing in popularity https://survey.stackoverflow.co/2025/technology/. It will have real threads soon and better type checking with ty (thanks to astral who also make uv and ruff). Python gives an incredibly tight integration loop since you don’t wait on compiling. Our kotlin projects are always at least 2x slower for ci/cd builds. I like typescript, but working with it in IntelliJ is incredibly slow.
Python's great until you have to refactor a large code base
Java compiles as fast as go, so not really sure what's the problem - you can basically use it in an "integration loop" with no problem.
What advantage do old languages have that can’t be overcome or at least reduced to insignificance?
The 50-year head start in training data, runtime, and ecosystem? That may not be much, because LLMs are rapidly accelerating software development. LLMs can also generalize: take what they learned for one language and apply it to a “similar” language (and I think most modern languages are similar enough for broad effective translation: all have records/unions, objects, functions, types, control-flow, exceptions, and more). Some fairly recent languages (e.g. Rust, Swift) already have comparable runtimes and ecosystems to older ones, from human-driven development acceleration and concept generalization.
In a recent study, LLMs solved the most exercises in Elixir (https://autocodebench.github.io Table 4). Anecdotally, I’ve heard others say that LLMs code best in Rust, and (for UI) Swift. More importantly, I don’t see an older language advantage that is widening from LLM use; an older language probably is better for most use cases today, but any written code can be translated or regenerated into a newer one.
> I don’t see an older language advantage that is widening from LLM use
A classic one is C++. Microcontrollers like esp32 cost about $10 these days, for a machine more capable than an early PC.
One downside though is that you typically need C++ to program them, and the barrier to entry with C++ is very high, especially for non-programmers.
LLMs remove that barrier so that anyone can create powerful embedded devices - programmed in C++ - without knowing anything about C++.
> Why would anyone create a new language now? The existing ones are "good enough", and without a body of examples for LLMs to train on, a new language has little chance getting traction.
Compiler writing can be an art form and not all art is for mass consumption.
> Java has won (alongside many other winners of course), now the AI drawbridge is being raised to stop new entrants and my pick is that Java will still be here in 50 years time, it's just no humans will be creating it.
This makes no sense to me. If AI possesses intelligence then it should have no problem learning how to use a new language. If it doesn't possess intelligence, we shouldn't be outsourcing all of our programming to it.
Intelligence is not a well understood concept. "AI" is also not a well understood concept - we have LLMs that can pick up some novel patterns on "first sight", but then that pattern takes up space in the context window and this kind of learning is quite limited.
Training LLMs on the other hand requires a large amount of training data.
> This makes no sense to me. If AI possesses intelligence then it should have no problem learning how to use a new language. If it doesn't possess intelligence, we shouldn't be outsourcing all of our programming to it.
Perfection. You have made such an excellent. However, I don't want to detract from that but it's like, in reality, this is a completely obvious point but because of this AI/LLM brain-rot that has taken over the software programmer community, writ large, this is particularly insightful. It's also just a sad and unimaginative state we are in to think that no more programming languages will ever be needed other than what currently exists in March 2026 because of LLMs.
Programmers would create a new language when there is a fundamental change in hardware architecture such that the assumptions underlying the old programming languages no longer apply. Java is probably a poor choice for writing software in which most computation happens on GPUs. But I agree that someone (or something) will still be using Java to write new line-of-business applications in 50 years.
Mostly a tongue in cheek reply, but you might be interested in TornadoVM.
(Nonetheless, I agree with you)
Why would anyone play chess in 2010? The drawbridge is rapidly being raised on human competitiveness.
The vast majority of programming languages ever created never aspired to win and I don't think that's going to change now.
> Why would anyone create a new language now?
Same reason you'd ever create a new language — to start anew, breaking free from the shackles of backwards compatibility of the old language, having learned the lessons of the past.
The AI angle makes even less sense — surely we will want to create languages that are tailored for them.
As a Go developer, this is right on the mark. I’ve been hearing good things about Java lately, so I decided to check out the language for the first time since 2012 or something. And I was impressed!
The language maintainers have added so many great features while maintaining backwards compatibility. And slowly but surely improved the JVM and garbage collection. So after toying around for a bit, I decided to write some personal projects in Java.
After a week, I gave up and returned to Go. The build tooling is still an over engineered mess. Third party library APIs are still horrible. I will never invest even 5 minutes in learning that horrible Spring framework when stuff like Django, Rails, or the Go ecosystem exist.
The community, and thus the online forums and open source libraries, still approach engineering and aesthetics in a way that is completely foreign and off putting to me.
> I will never invest even 5 minutes in learning that horrible Spring framework
well there's your problem - why are you using spring for a personal project, when there's so many other simpler, lighter weight frameworks around?
> Spring framework when stuff like Django, Rails, or the Go ecosystem exist.
Django and Rails have a very similar model to Spring, so frankly this is just "I was lazy to learn a new tool and it must suck" kinda take. Is there a learning curve? Sure. Does it worth it? I would say for typical CRUD stuff, yeah. No matter how trivial it is you will likely end up needing something that is a single annotation away. But you may want to try quarkus over spring.
Yeah, don't use Spring. If I'm doing DI, I want compile time DI, so Micronaut or Quarkus.
What do you mean by "better than Go for industry purposes"?
I don't understand what "industry purposes" means and in what aspects Java is better than Go in your opinion (I can think of some myself, but I'm interested in your perspective).
Not the GP, but for really large code bases, Go is missing a few features that I've noticed:
1) No immutable types. My work team is a huge user of immutable data stuctures in Java to make sure data passed around to other teams isn't changed. Go doesn't really have a good way to do this.
2) Refactoring can be really annoying (or at least really noisy) because of public/private being defined by capitalization of method/field names.
3) Error handling isn't great. I love Go's errors being just normal values, but the `error` interface is awkward when trying to figure out what kind of errors can be thrown without having in-depth knowledge of the kinds of errors that can be returned. We regularly need to make different decisions depending on the kind of error returned. Knowing which errors can be returned in Go is not defined by the method being called (only in comments).
I think you want sum types which admittedly Go doesn't have in a matchable way. However complex error recovery is an anti pattern for Go.
> However complex error recovery is an anti pattern for Go.
Bit of snark from my side, but that's exactly what makes it less good of a fit for "industry purposes".
Go's error handling is possibly the worst out of any "modern" language, it basically copied C's errno which is not something you should have ever done.
This was exactly my experience when I first read about Go. I was so excited until I found they were repeating the c experience of check every bloody return value separately. That was the worst feature of c - why copy it
Why exactly do you have complex error analysis happening above a component that has the error? That's anti modular.
Because almost my definition you can't handle errors in the component, otherwise you would have a conditional and not an error.
E.g. if I do some IO like "make a copy of these files" and get an error/exception, it's only the caller or maybe even that caller's caller that can properly deal with this condition (e.g. to decide that we will skip the erroneous files or retry).
> No immutable types (in Go)
The typical answer is opaque types with only readonly methods exported. Not elegant, but it’s there. I guess it’s arguably not a “good way” to do it.
In fact it was “the Java way” for many years and “useless getters” was always a big complaint about Java.
Hey it's better in Go. In Java it's getFoo(). In Go it's just Foo(). Saves three bytes, and three keystrokes if you program by hand and don't autocomplete!
I do agree to a certain degree, but with getters/setters you could properly hide/set to read-only fields.
This is not a dig at Go and this will be controversial but I so struggle to see what problem or area Go is solving outside of CSP. It's a nice language it just feels far too simple and I am really convinced of it as a systems language over Modern C++ and if you want that alternative then we have our rather oxidized friend that seems to more substantial. That's just my take.
I code Go at work. I've been using it for just over 3 years. I really like it. I prefer Java, but Go is a much more ergonomic C and its a very pragmatic language. Except for the *%!@ error system, that can burn in hell.
Go can't compete with Java bc it's not in the same category as Java.
- Java is a high-level, multi-paradigm programming language
- Go is designed as a systems language to supersede C projects at Google
Now Go identifies as a general purpose language that competes with Java? It's a free country, I guess.
How is Go not high level? What makes it "systems" language? That's just marketing.
It is a language with a fat runtime, running a garbage collector. You just burn it into the binary and call it a day.
(just like modern Java can burn its runtime / GC into the binary)
No, not just like. You're downplaying significant differences between the two that do in fact matter. So much so in fact, that you're just wrong. Stop spreading misinformation.
GraalVM indeed does a lot more than Go, it's a full optimizing compiler while Go does very little optimiations.
But burning a JVM next to a jar file is not hard at all, one could make something like cosmopolitan.
Go use cases overlap the most with Java. I think the reputation you mentioned comes from Google using a lot of C++ for high-level things others would likely do in Java, so they see Go as a replacement for C++ in some areas. (assuming you meant C++ not C)
> I think the reputation you mentioned. . .
Actually no. Go was designed from the beginning as a systems language as a C replacement.
In what way does that "design" show up in Go, besides marketing?
It's replete with oddities and limitations that signal "ah, this is because systems language."
Go’s type system, for example, is very much a systems-language artifact. The designers chose structural typing because it was lighter weight, but provided enough type safety to get by. It sucks though for enterprise app development where your team (and your tooling) are desperate for nominal typing clarity and determinism.
The error handling is like a systems language for sure, I'll agree on that.
But where do Go's docs or founders call it a C replacement? gf000 asked where this is mentioned besides marketing, but I don't see it in the marketing either.
Now that Go is styled as a Java competitor its framing is different. But here's an old golang.org archive for fun:
https://web.archive.org/web/20091113154831/http://golang.org...
The main page title *Go: a systems programming language*
It still sports all the low-level stuff too, pointer arithmetic and all.
And a fat runtime with a garbage collector. Like people can write all sorts of programs with a GC, that was never the issue.
But then just stay truthful, otherwise C# is also a system PL.
"industry purposes" likely equates to "enterprise software development." And that assertion is 100% correct.
Exceptions
Ya, that seems to be a misunderstanding. "Industry purposes" covers a huge range of stuff. Go is pretty good for systems programming where Java isn't really an option due to the fundamental limits imposed by garbage collection and lack of pointers. Java is pretty good for higher-level application development where occasional GC pauses are tolerable (the GC pauses are rare and fast now, but they still rule out using Java for certain purposes).
Are you sure about Go's garbage collector doesn't have pauses? AFAIK they are worse than modern Java's garbage collector [1].
I'm not sure it's even better than Java's, especially for modern ZGC (and you can choose your GC in Java). Definitely less configurable. I would say most of online comments about Java's GC are long outdated.
For example, in web servers a lot of work is request-response, so it's convenient to utilize generational GCs (so that each request data would fit into "young" generation). Similar to arenas, but without code changes. Go's GC is not generational though, so you should care about allocations.
https://codemia.io/blog/path/The-Evolution-of-Garbage-Collec...
Java's GCs (plural) are hands down better.
Hell, I even had a use case where serial GC was actually the correct choice (small job runner process that needed to be extremely low memory overhead). It's nice having options, and most of those options are extremely good for the use cases they were designed for.
Ok, which one do I choose then, with what configuration? How much time do I need to spend on this research?
How do I verify that they are actually better? Is the overall performance of my program better? Because that's what I care about. I of course do include memory usage in "performance".
Do you need extra-low latency, even at very high percentile and are willing to give away a bit of throughput for it? ZGC
At almost every other case: G1 (the default, just don't add any flags).
Do you want to trade off using less memory at the price of some throughput? Decrease heap size, otherwise don't add anything.
That's it, in most cases just use the default.
> I would say most of online comments about Java's GC are long outdated.
They are not. Feel free to look up literally any half-decent benchmarks. If Java's on par or better than any other language of note, check the memory usage. It's standard for Java to have 5-20x the memory usage for about the same performance. The memory floor also seems to be in the hundreds of megabytes. Ridiculous.
> For example, in web servers a lot of work is request-response, so it's convenient to utilize generational GCs (so that each request data would fit into "young" generation).
No, that's a job for arenas. Generational GCs are mostly a result of Java's limitations, and not a univerally good approach.
> Go's GC is not generational though, so you should care about allocations.
You should always care about allocations. In fact, the idea that you shouldn't is a big part of Java's poor performance and design.
No-one ever claimed that Java didn't use a lot of memory. The "comments about Java's GC" used to be about pauses, mainly. Java programmers don't claim that the JVM is conservative with memory use. That said, 5-20x.... nah. Maybe for a toy 'hello world' sized program, but not in real usage
GC pauses on modern JVMs are < 1ms (ZGC & Shanandoah)
Go's GC is orders of magnitude behind Java's.
Go has gc too and arguably worse one than Java
Yeah but I do like not having to give Go several flags to do something reasonable with its memory
The "reasonable" thing go does is pausing core threads doing the actual work of your program, if it feels they create too much garbage so it can keep up, severely limiting throughput.
I think this is a misunderstanding. If the program out-paces the GC because the GC guessed the trigger point wrong, something has to give.
In Go, what gives is goroutines have to use some of their time slice to assist the GC and pay down their allocations.
In Java, I believe what you used to get was called "concurrent mode failure" which was somewhat notorious, since it would just stop the world to complete the mark phase. I don't know how this has changed. Poking around a little bit it seems like something similar in ZGC is called "allocation failure"?
The GC assist approach adopted by Go was inspired by real-time GC techniques from the literature and in practice it works nicely. It's not perfect of course, but it's worked just fine for lots of programs. From a purely philosophical point of view, I think it results in a more graceful degradation under unexpectedly high allocation pressure than stopping the world, but what happens in practice is much more situational and relies on good heuristics in the implementation.
A lot of the answer is that if you can do more work while generating less garbage (lower allocation rate) this problem basically solves itself. Basically every "high performance GC language" other than Java allows for "value type"/"struct"s which allow for way lower allocation rate, which puts a lot less pressure on the GC.
How much less allocation rate? Value types are an important thing and fortunately they are coming to Java as well. But they don't decrease allocation rates nearly enough in every kind of software. They may be a necessity in games/certain computations/low-lat trading, but for a typical web server they don't matter all that much - people are using identity having objects in value typed languages the same way here. Especially that with thread local allocation buffers in Java single-use object allocations are not particularly expensive to begin with - live objects are evacuated and then the whole buffer is reset.
So unless you claim that there is no software in Go/C# where the GC is the bottleneck, no, the problem absolutely doesn't solve itself.
And yet Java outruns pretty much all of them, because it doesn't actually allocate everything on the heap all of the time. And you've been able to declare and work with larger structures in raw memory for ... 20 years? You mostly don't need to, but sometimes you want to win benchmark wars.
And of course it's getting value types now, so it'll win there too. As well as vectors.
Post benchmarks. No, ones where you use 20x the memory of Rust to do the same job 1% faster don't count.
You don’t have to do that with Java either.
That's a very shallow argument.
If it were shallow, it'd be easy for them to fix
Backwards compatibility, every vim and emacs and bash enthusiast should know about it.
It's easy for the USER to fix, since there are flags available. In the day of LLMs it's also easy to find out about those flags and what they do. And if it's so important, testing shouldn't be supremely hard, either.
Do you mean backwards compatibility for things that rely on the default settings? The defaults have already changed across Java versions and also depend on the system.
Normally when you run a non-Java binary, it uses very little memory to start, doesn't have a limit, and returns memory to the system when it frees things. Supposedly you can set JVM flags to do all that, but performance probably suffers, otherwise they would've just done that. So in practice users are always setting the flags carefully.
I write TypeScript daily and honestly it is not about being scared of Java. The ecosystem just makes more sense if you are already building for the web. You write your frontend in JS/TS, your backend in the same language, your build tools understand it natively, and you share types between client and server. That is a hard thing to replicate in Java even if the language itself is technically better in some areas. The barrier is not cultural fear, it is practical convenience.
With SSR/HTMX/HATEOAS the amount of code executed on client side is relatively minor and does not justify the unstable JS/TS tooling and frameworks, and the security nightmare which is NPM-based supply chain.
My experience has been that developers say that they’ll share types between the frontend and backend, and then in practice they just duplicate it.
Different tools for different purposes...which is good/right.
TypeScript is a superior programming environment for the browser, for sure. Using it on the server? Why not, if you're not trying to scale (in capacity, or functionality).
Language-agnostic serialization exists for a good reason. It's not always right, but it's almost always the right thing to do.
What if you have a mobile app? Rest APIs? The argument doesn't work. Every backend language has ways to generate specs/types/clients from the APIs code.
> You write your frontend in JS/TS, your backend in the same language, your build tools understand it natively, and you share types between client and server.
that's an excuse imho. It's a post-facto justifying using js on the serverside because of familiarity.
I know because the exact same reason was given for GWT (google web toolkit), and that failed pretty horribly (despite it being quite good imho).
GWT was a huge success, and eventually became obsolete -- which is not the same as "failing horribly".
It took a long time for the web ecosystem to build up the capabilities that removed the need for GWT.
For a while, it was quite a good way to build and heavily optimize certain kinds of web client applications.
Yeah, I believe some ex-Googlers even claimed that writing Gmail was simply impossible at that time with ordinary JS, and the abstraction behind GWT was an absolute necessity (though maybe the frontend part was not all that important - closure compiler is still alive though)
On the other hand, gwt did not gain much traction, and the majority of frontend developers disliked it (granted, they do prefer javascript+css rather than coding the frontend via gwt widgets).
The biggest problem with Typescript in the modern era is that LLMs are pretty bad at it, at least as compared to some other languages that are more well suited to LLM generation. What you say may have been a boon in the olden days, but it is hard to justify now. It is difficult to avoid Typescript/Javascript in the browser, sure, but now it's just as fast to duplicate everything in another language for the backend and at least gain the advantages on that end.
Maybe this is just a question of taste but I never could get along with Javas (or Kotlin's) tooling.
Primarily working in Vim/Helix works for most languages from Nix to Typescript or Rust and C, but Java just never worked quite right. It also generally felt like it had a worse story around tooling from a DX perspective, something like Golang or even npm feels a lot lighter than the molasses of JDK management and gradle et al.
> Maybe this is just a question of taste but I never could get along with Javas (or Kotlin's) tooling
Are you joking? IntelliJ is without a doubt the best dev tooling environment available.
No, I'm not. Through university (and even before) I have access to their full suite. I have tried to use PyCharm, GoLand and Idea.
Idea was useful for Java but felt quite slow and even with vim bindings was a pain to navigate. Learning the shortcuts helped but it never got quite as fast as helix/vim for general editing (especially as my work usually is a polyglot). It might be the best for Java (compared to eclipse or bluej) but that does not mean it fits my workflow/way of work.
PyCharm/GoLand both are "nice" but it did not feel better/more efficient than pylance/pyright)/gopls + vscode/helix. The only I still occasionally use is DataStorm as it is quite a nice SQLite/PostgreSQL client.
edit: fixed typo from gostorm -> goland
GoStorm?
Thanks for noticing the typo, must've mixed up the PHP and Golang IDEs
Besides doing yourself a disservice of not using a proper IDE, what exactly makes Java not writeable in vim or the like? Like it's a pretty simple language with not much magic going on.
And Java has some advantages that are hard to beat. It performs better than Go and builds just as fast (at least when not using some popular build tools) while offering unmatched deep, low-overhead observability.
People might think they may enjoy another language more, but the portion of people who eventually come to regret choosing Java is probably lower than that of any other language.
> It performs better than Go
Do you have some sources or experiences to share on this topic? I'm very curious. My experience is the complete opposite.
At my previous job there was a Java web application and running in Kubernetes (1 vCPU and 1Gi of memory) was able to deal with at most 80 requests per second, using up almost the full 1 vCPU and ~600-700MiB of memory. That was a bit disappointing, since we were supposed to support at most ~1000rps on this API, 13+ pods is a lot, and we felt "software could do better".
A reactive guru from another team told us we should use a reactive stack, so he came in and rebuilt the app using the reactive stack. Now it was doing about 120rps on one pod (about the same memory usage), which was a good improvement, but still disappointing.
One guy on the team was motivated to rewrite the API in Go as a proof of concept, and we were blown away. With the same 1 vCPU it was now able to handle 400 requests per second, while using ~100-200MiB of memory, and having approximately 20% better response times.
> builds just as fast (at least when not using some popular build tools)
I find this a little bit of a cop-out, because almost everyone is using the popular build tools. And it's quite a chore to build a full application without those popular build tools. With Go, all batteries for building are included.
From your description it sounds like you're comparing an old Java program running on an old JDK with a new Go program running on a new Go runtime. These days Java has virtual threads (similar to Go's goroutines) and doesn't need a "reactive stack", and its optimising compiler and GCs blow Go out of the water without breaking a sweat.
I mean, what is old? How far along are frameworks these days, and what are companies using?
That team was using Java 17. Java 21 was just released and frameworks had no meaningful support for virtual threads whatsoever.
In my experience, most companies using Java are chronically multiple versions behind (e.g. some of my friends still in the Java world are on 11).
Perhaps you can share some sources which prove that Java's performance blows Go out of the water without breaking a sweat? I have not seen any such articles about that in the past 3 years, besides the cherry-picked cases where the JVM JIT can optimize some small algorithmic part of the program on the fly (which is not relevant in most web applications).
I'm happy to stand corrected.
Edit: I found this one using a quick search myself https://medium.com/@mohnisha/java-vs-golang-performance-test... I'll check it out and see if I can reproduce it myself too. Still too bad about that gargantuan memory usage, but I guess memory in the cloud is cheap.
> Java 21 was just released and frameworks had no meaningful support for virtual threads whatsoever.
Spring was ready on day 1, as virtual threads had been an experimental feature since Java 19. Spring Boot added support within a couple months.
> In my experience, most companies using Java are chronically multiple versions behind (e.g. some of my friends still in the Java world are on 11).
And that's on you.
> And that's on you.
Sorry I have to defend my pride here a little bit. When I joined my previous company, the entire company was on Java 8. When I left every app in every team there was up-to-date on the latest LTS release at the time, 17. I assisted many teams in upgrading their Java, Spring, etc, and inspired even more.
I would argue that I'm one of the last people who you could blame for most companies being many Java versions behind...
So what's the issue then? You'd be able to bring other teams to current versions of Java and frameworks, which have all been using virtual threads for the past 3 years.
>> In my experience, most companies using Java are chronically multiple versions behind (e.g. some of my friends still in the Java world are on 11).
> And that's on you
What most companies do is on them?
Well, what frameworks were used? Also what is behind the web requests, what were they doing? Because it's comparing mostly frameworks, not languages.
As for the build tools, unfortunately the scene is not the best on Java - but javac itself is indeed fast.
Yeah javac is pretty great. I was doing Kotlin for some time and I was getting very annoying by how much slower and slower running tests and doing full builds became. I thought it was some issue with the JVM ecosystem. Then I started a project with pure Java and I was blown away by how fast it was. Unit tests in my IDE running as fast as I'm used to in Go. And indeed I was surprised by the speed of the compilation step of the build too. Perhaps Kotlin is doing better now, haven't touched it in a few years, but yeah, Java made some great steps there in the past decades.
> and builds just as fast
Source? I'm not saying you're lying but I have never seen any Java project build as fast as Go
Use javac directly, in a recent JDK, to compile lots of files at once (i.e. one invocation of javac to compile multiple files) and you'll see. The speed is over 100,000 lines/sec: https://mill-build.org/blog/1-java-compile.html
Seriously a need for a new build tool in Java that doesn't fuck around too much.
Check out mill from the link. It’s quite good.
Oh sweet. Former Java dev turned Go dev like a decade ago, this looks close to what I want.
100% this. Ant was bad in many ways, but at least it was lightning fast. Gradle is just tragic.
Try mill from the link! https://mill-build.org/mill/index.html
I dont think the Spring ecosystem is bad. In fact, its one of the more stable frameworks. Even spring AI which is built for AI agents a new use-case is very intuitive if you take time to learn its abstractions. Usually doesnt take more than a day of reading docs and writing some try-out code. The thing I really like about Java is the stability of its packaging ecosystem. Maven is XML (yuck) but is okay with the IDE integrations. Gradle has advanced features often missing in Python / Go such as build caching. The OOP stuff is also good because it scales with very large code bases. In, fact frontend esp React adopted a functional style which leads to complexities associated with hooks. A mixed approach is usually better. Overall, the only bad thing are the multiple unnecessary abstraction layers which are a pain in any language. Rest of Java is quite good.
"a solid foundation for the future" is faint praise for a language that has been around for over thirty years.
> It has become a best of breed language
To me it lags significantly behind .net (runtime) and C#/F# (language). I don't see Java catching-up.
They trade blows, and have different philosophies (complex runtime, simpler language vs the reverse).
E.g. on the GC side Java is ahead of any other platform, especially with the low-latency ZGC garbage collector.
The counterpoint is that Java has so much SOTA GC work precisely because the language makes writing efficient code that doesn't heavily tax the GC basically impossible.
Tell me you haven't looked at Java in 15 years without telling me.
Given that the vast majority of non-GC language code does a terrible job of managing memory, it's not difficult at all for the JVM to win out on efficient, reliable systems.
To be clear, I think that GC is absolutely the right approach, you just need an object model that lets you write idiomatic code that allocates an order of magnitude or 2 less. Once Valhala is (finally) released, the Java ecosystem will start to have the tools to write efficient code (the same tools that C# has had for ~2 decades now), but until then it's just completely impossible to write object oriented code in Java without millions of allocations per second.
I would love to have a Java compiler with the capabilities of the .net compiler. To make incremental builds to aid code completion including type information, looking past simple syntactical errors, fixing them, and continuing compilation.
Currently, this is “magic” embedded in eclipse, IntelliJ, and maybe a bit in the vscode plugin. Imagine having a Java LSP running that can provide all this information while typing.
.net has had this for ages. From a language design I think that is wonderful.
Java LSP backends are basically headless Eclipse and NetBeans, they definitely go beyond syntactical errors.
There's also the upcoming Metals v2 that's using another compiler frontend optimized for performance, Google Turbine: https://metals-lsp.org
Actionable diagnostics for Java aren't implemented yet though.
It also slows VS code a lot, is not properly documented, and still relies on concatenating strings together, due to Source Generators interaction with attributes.
On the contrary, as someone that earns their bread using both ecosystems, .NET is still pretty much tied to Windows, regardless of .NET team efforts, most shops going with macOS or Linux are former Microsoft shops saving on server licenses or giving Macs to their devs.
There are many platforms where .NET doesn't have an implementation, a phone to call their own (even if ART isn't proper Java, WP is no longer around), embedded systems, including factory and military weapons deployments (PTC, Aicas, microEJ), copiers (Xerox, Ricoh), phones (Cisco),....
C# is definitly better than Java dealing with value types and low level programing, or being embraced by the game development community, however not sure if the featurities of last years is the right path, I am starting to feel I should just reach directly to C++ instead.
Java is 4th on tiobe.
Bright future for it just means it is not planning to become 40th or 400th.
(My prediction - in next ten years java will always be among top 6; new language might come to the very top and some leapfrogging game between c# and java)
Tiobe once rated Visual Basic ahead of JS. I would rather believe some future reading octopus than that absolutely useless ranking.
Nonetheless, I agree with your take.
tiobe is garbage and should never be given any credibility.
There are no FactoryFactorys in Java. Never have been
Enterprise space architecture is not picky, all programming languages get a place when they manage to hit big at corporate life.
It can be Yourdon with C and Pascal, Booch with Smalltalk and C++, Patterns with Smalltalk and C++, UML with Ada, C++, Smalltalk and Java, Rational RUP , Java and .NET application servers, Kubernetes with WebAssembly microservices,....
Ever looked into Typescript with effects, pretending to be Haskell?
> All those people using typescript (could be using Java - but the culture doesn't want them and consider them heretics for not embracing religion of OOP and FactoryFactory)
I assume you're specifically talking about the backend and not suggesting that people write Applets or use GWT or something.
The fact that you mention Go explicitly hints a real issues with Java.
Hey even Go has got effective `FactoryFactory` stuff in a lot of open source projects. They just name it differently.
Java isn't even true OO. The only truly OO programming languages that I know of are SmallTalk, Obj-C, and Ruby
Says a single guy who may have coined the term, but that's not how words work. The industry's millions of devs use it differently, so the de facto meaning is that java is an OOP language, and the original is closer to the actor model.
The problem is that many jobs with Java (that I've found) lean so heavily towards OOP that it's part of the job description. I just don't enjoy OOP and find that there's almost always a simpler approach, and to have it prescribed as part of the engineering culture will always steer me away.
Most of backend development on Java is procedural with OO syntax and ability to replace something in the chain of calls with stub in tests. Spring beans are usually stateless singletons containing a few references.
Yep, I find it easier to think of a Spring (or any DI) Bean like a parameterized module that is applied at runtime, the code within each bean is pretty procedural.
Front page, 82 comments, comment 2 hours ago…why is this the top comment? “People who write Typescript could just be writing Java except they’re scared of being outcasts for not using design patterns” is bait, not a serious technical opinion.
Oh. That’s why it’s the top comment.
> hell its better than Go for industry purposes
Yet if you ask people in the bay area, especially the those who are under 35, they would tell you that "Use Java? Over my deadbody". It's just amazing that people always chase shiny new things.
Right because golang is like 2 years old and new o.O
There's so much Java development in the Bay
chasing the new shiny? or running away from the zombie?
> hell its better than Go for industry purposes. [...] the drawback with Java will always be the CULTURE
The industry purpose for Go is that all codebases look more or less the same, so workers can jump into any project they've never seen before and instantly feel like they wrote it themselves. Google talked about that a lot around the time Go was released. It is why they created it instead of just adopting Haskell or something.
Some of that simply comes down to the language not allowing much creativity, but without the culture developers would still find a way to mess with outcomes. You can still write crazy Go code if you want to. The culture is the piece that matters. If Java doesn't have the culture, how does it fit in industry?
The drawback is also the JVM. Its a heavy, bulky VM. The alternative being Go that is much lighter.
With all due respect, I'm fairly sure that anyone using "VM" the same way as you do here really think of it as a container or what.
It's a runtime, and go also has a similar, fairly fat runtime. It's just burnt into the binary instead of being shipped separately. (Hell, even Rust has a runtime, it's just very very lean compared to languages featuring a full GC like go and java)
With LLMs as they currently stand, and with the reasonably confident hope they will get better why even have anymore languages. Shouldn’t we just have everything coded in the most performant language which would be Assembly or C?
I am captivated by your thought process.
[dead]
I didn't use Java since 7, but from people that do - nowadays you basically don't code Java, you code Spring Boot. And that has all the bad things you think when people say "Java".
I don't know if it's true though.
Spring Boot isn‘t bad. It‘s opinionated about configurations and dependencies. Its main advantage is that you can start shipping production-quality code very quickly, focusing on business problems rather than anything else. Vibe coding on it is more or less stable, entire apps can be built solo in a few months. And it‘s easy to do fullstack with SSR based on Thymeleaf and Htmx. It is absolutely superior to anything that exists for node stack.
And then there‘s also Micronaut, if you prefer compile-time setup to Spring.
There are more Java devs than people in my home country. Like how could you even give a single description for all of them? They all work on vastly different stuff, from low-latency trading to robotics, to regular old CRUD. Not even the CRUD part is as monotonic though as you make it out to be.
There's a lot of programming that has nothing to do with SpringBoot - and I say this as someone who works in a backend team that uses SpringBoot for all our apps.
You're talking to specific people.
A completely different culture of Java usage can and does exist a lot of places. It is absolutely true that success creates a certain ossification of practice. But SpringBoot is not necessary, any more than Guice or any other framework-y thing.
That's weird. Back when Java 7 was a new thing, people used Spring (Boot wasn't there yet) even more to compensate for the lack of language features. Also back then most projects still used XML configuration, so you actually write more Java code in modern Spring. Because Spring Boot uses Java configuration classes by default (although you can still use XMLs if you need for some reason).
I’ve been working in Java for 12 years, my entire career. I have never worked on a Spring project.
> Nowadays you basically don't code Java, you code Spring Boot. And that has all the bad things you think when people say "Java".
Subjective experience, but largely agreed.
Vague rant that summarizes my own experience: major version updates kind of suck, even if Spring Boot is still better than regular Spring (I've gone through the XML hell, was not fun, even less so with a separate Tomcat instance that we had to deploy to, instead of an embedded one). In practice their huge effective pom.xml also leads to conflicts when your package needs something else and it feels a bit arcane to override things. There are things that have underlying technical reasons for being the way they are but seem stupid from afar - like how @Transactional doesn't work when called from within the same bean. Personally I also prefer code over convention for configuration and initialization so the whole annotation driven setup feels quite annoying and difficult to debug when things go wrong - but even the code configuration isn't always great and sometimes it feels like they have abstractions for the sake of abstractions. Spring Boot also often brings friends like MapStruct or Lombok or Mockito which add even more dynamic behavior and issues when you update JDK, alongside slow testing with JUnit and unpleasant debugging of jumping through numerous abstraction layers. You don't strictly have to, but people will.
I probably should have written down every complaint with exact details (so those could be picked apart as user error) over the years that I've been unfortunately maintaining and building shitty software with Java, but I will say this - modern Spring Boot isn't wholly horrible, it has a pretty rich ecosystem and you can do a lot of things with it, but the overall vibe I get from it ofen can be summarized with "Eww." I'd end up using it because I have to, or because it's a means to an end ("Hey, we need to build an event-driven system to integrate with a bunch of others, you have two weeks"), not because I want to.
For the sake of comparison, I believe that for plenty of the folks even Dropwizard would be worth a look: https://www.dropwizard.io/en/stable/ it is more or less like some glue around a bunch of idiomatic packages in the Java ecosystem and it's not horribly hard to integrate something that you want yourself (e.g. Dagger 2 for DI, at this point I'll take anything that does as much as possible at compile time https://dagger.dev/dev-guide/).
Or, for a more modern spin, Quarkus isn't too bad either https://quarkus.io/ or maybe Micronaut https://micronaut.io/ or perhaps Helidon https://helidon.io/ with neither of those being strong recommendations - figure out what you like for yourselves. For people that have been luckier than me, that might as well be the very same Spring Boot, just on better projects. JVM is a pretty cool piece of tech though, and so are the JetBrains IDEs with their refactoring features and nice Maven integration.
Once i heard a manager explain "we must get rid of anything Oracle, including Java, because of license reasons". I see this attitude everywhere since.
JavaScript people are too afraid to use Java, that is why something like TypeScript exists.
And for personal projects, C# has become a better and more fun "just works" platform.
I wouldn't count myself as a JavaScript person at all, and usually avoid it where I can, going to some length, to make pages static, if possible. So I am not exactly in the group of people you are attacking.
However, I am afraid of the Java coder who is decorated as senior, has sway due to their position, and who will tell me, that something, that is a simple function, shall not be a simple public static "method", but must be wrapped in yet another object, which I need to instantiate, because OOP, and because obviously I don't know what I am doing, or because it doesn't fit existing "coding practices/style" or "Java style". I am afraid of the Java coder, who for years has not touched anything but Java, because their jobs didn't require anything else, because so many companies want Java. I am afraid of the one who throws around jargon like "dependency injection" all day, without ever using simple terms, or realizing what those things are looking like in another paradigm.
Lord, please save me from ever having to work with such obnoxious and uninformed, learning resistant people. This actually may be a straw man, but even one such character matching one or more of those traits, seated above at the seniority ladder will make a mess, that everyone else has to live with.
> So I am not exactly in the group of people you are attacking.
I wasnt attacking anyone.
Developers are used to the lack of type-safety in JS, and assume that having to code in a type-safe language is something hard. Ive seen this attitude multiple times, it is a known topic.
The issue you are describing is what the author on top mentioned, the culture. It is not just Java, the "enterprise style" coding has infected other languages too. It is the result of how new developers were educated in a time when for example code performance or code readability were only abstract considerations. I fought that style myself multiple times in the past. But thankfully it is going away now.
We are more or less in "chained function call hell" now.
I mean, sometimes managers are uninformed and say stupid things?
You can use any of the other jdk builds from the plethora of other vendors and have zero interaction with Oracle.
I absolutely hate Oracle as a company, but they've really done a good job with Java stewardship. They actually open sourced the entire language / jdk and a lot of the tooling that used to be proprietary.
They still love to play the old Oracle tricks, so I'd rather not use any of their distributions. But the actual work that they do on the ecosystem has been a positive in my opinion.
You don't have to tell all this to me, or try to convince me. I was just describing what the general attitude is. Oracle's behaviour is a risk, even if Java is open source.
That and also the JVM is a marvel of engineering with millions of hours that were poured in by smart people over the last 30 years.
It can be as fast a C, supports a multitude of languages, introspection, surveillance etc.
JFR is one of my favorite things about the JVM. Such good tooling to figure out whatever it is you are having problems with in production.
I've also used Eclipse MAT to find tricky dangling references to objects that caused memory leaks. Definitely not as polished, but extremely useful.
I program in Java for more than 15 years now. I can resonate with people hating the language from it's early days due to the experience with all the enterprisy features and over abstractions. Or confunding Java with the Spring ecosystem. But Java came a long way over the years. It's now what many would call a "modern" language. It's less verbose, has many of the features people find appealing in Scala and Kotlin and it can even compile to native binaries using GraalVM. This made building CLIs in Java feasible. Or lambdas.
I recently worked on a Go project and my task was to make it more configurable at build time and start time (add plugins / addons, make it possible to reuse from other libraries and tools). Turned I had to create *Factory and *Providers, even though I did not want to.
It's easy to avoid "AbstractFactoryProviderBuilder" if everything is hardcoded. Try to make it reusable and extensible, and I bet you write one yourself.
> It's easy to avoid "AbstractFactoryProviderBuilder" if everything is hardcoded. Try to make it reusable and extensible, and I bet you write one yourself.
The first domino is opting for OOP. AbstractFactoryProviderBuilders are just the inevitable downstream consequence of that initial choice. No need for factories if you don't traffic in objects in the first place.
Objects. Just say no.
Mmm, no, I don't see why OOP has anything to do here (any examples?).
I did not use any inheritance. In general I would say OOP craziness faded long ago (in Java too), together with XML. Interfaces -- yes, are very much alive though.
I'm not using OOP to mean presently unpopular facets of OOP, to the exclusion of presently popular ones, I mean all of OOP. It's pretty hard to need factories, let alone factory factories, when one isn't using objects or classes.
A friendly joke in response to the claim that sufficiently complex code always ends up sprouting OOP abstract nonsense.
Unless you are using a strictly FP language, you are always basically using objects.
And all the stuff like factories and everything exist in FP as well, it's pretty short sighted to say otherwise. These are patterns that may or may not be useful in a given case. Sometimes a language feature can replace them (e.g. pattern matching ~ visitor pattern, but not even this is a full match see closed vs open hierarchy), but in most cases you just call them something else/don't have that problem because you are not writing that big of a software.
Bit of an extreme position, no? Languages without OO tend to end up reinventing it. Like the Linux kernel style of "big C structure with function pointers": that's just a vtable which you have to maintain by hand. Or, god help you, trying to do COM in C.
What's a good codebase that is very large but without either OO or pseudo-OO?
I totally agree one ought not use a non-OOP language for OOP. Right tools for the job and all that.
I work on large (but private, so I cannot share, sadly) FP-style codebases. The code style is stateless functions grouped in modules that operate on data-only structs in a factory line manner. Typed boundaries for correctness, short and maintainable functions for clarity. No member functions, so no vtables.
I've never seen such code need or use OOP design patterns. I'm just very gently pushing back against the idea all code devolves into OOP spaghetti in due course. It doesn't! There are better ways. :)
Lack of virtual threads was its biggest remaining problem because this made the common ways of doing cooperative multitasking very ugly. Go's big thing was having that from the start. Maybe now that Java has it too, it's set?
Though JS will still have the least boilerplate because of the way it handles types.
IMO, Kotlin coroutines are better of Go's goroutines, although they are a little different beasts to compare honestly (apples and oranges). Go inits goroutines on stack, but min size is 4KiB, so it's not trivial to grow them. Also you need to watch over and destruct goroutines manually to prevent memory leaks (using
)And create a separate channel to return errors from a goroutine. Definitely more work.
Kotlin coroutines don't really exist. They're a (very neat) programming trick to support coroutine-like behavior on the JVM which doesn't support coroutines. If you look at the bytecode it produces, it honestly is a mess. And it colours your functions too: now you have be ever careful that if your function is running in a coroutine, there are certain things you should absolutely avoid doing in that function, or any function called by that function (like spinning the CPU on loop without yielding). In Go, you don't have to worry about any of this because the concurrency is built-in from the start.
Also I don't understand "it's not trivial to grow them". It is trivial to grow them, and that's why Go went this way. Maybe only 0.1% or fewer of use-cases will ever find any issues with the resizing stack (in fact probably the majority of uses are fine within the default starting stack size).
> Kotlin coroutines don't really exist. They're a (very neat) programming trick to support coroutine-like behavior on the JVM
Well, guess how coroutines are implemented in Rust/C++/everywhere else!
Nonetheless, I do think that java virtual threads are superior for the vast majority of use cases and they are a good default to reach for for "async" like code.
>you need to watch over and destruct goroutines manually to prevent memory leaks
No, you don’t. Any stack-allocated resources are freed when the function returns. WaitGroup is just there for synchronization.
It is, but your typical backend code isn't dealing with that most of the time. You can just use blocking I/O in handlers.
I think there is something to say for compiling to native code, having binaries in the ~25 MiB range, being able to run in distroless containers, being able to run a web application with less than 100MiB of memory and startup times measured in milliseconds rather than seconds (sometimes dozens of seconds).
Don't get me wrong, I like Java and don't very much like the Go language. But Java has a lot to improve upon still.
Small java programs start up well in the milliseconds.
I don't really think it's fair to compare some old jboss monstrosity doing the job of a whole kubernetes cluster to a dumb hello world server written in go.
Sure, java startup time is and will probably always be worse than putting everything into a single binary - but it is way overblown in many discussions. I have a bunch of Quarkus services on my home server and they start up immediately.
With Quarkus (and other new frameworks) you can have webapps with less than 100MiB. Startup times in a couple of miliseconds. CLI apps, with limited number of third party libraries are under 40-50MiBs.
You can have a <20MiB Graal-compiled binary for a Java project if you use a lean framework like Micronaut. Memory footprint is 5–40 MB RSS.
But with graal isn't the min compile time on avg hardware like a minute?
Yeah, but you only have to do that before shipping. You can just test/develop with "normal" java, you even get hot-reloading.
I think astronomers could measure the age of the universe in nano-Valhallas. Every year, it feels 50% closer to completion...
In all seriousness I'm happy with what Mr. Goetz and the team have done. Sealed interfaces (java 17) + exhaustive switch statements (java 21) means we now have union types in java! And instead of jumping on the async/await bandwagon we now have a more general solution that doesn't lead to API duplication (virtual threads). But Valhalla has been a veeery long time coming.
'Tis true. At the same time, Project Valhalla will be the most significant change to the JVM in a very long time, and probably its best chance to stay relevant in the future.
If we ignore the fact that value types likely won’t ship before we have flying cars, Java has evolved greatly. I really like how they’ve solved concurrency, but I dislike how they’ve handled modules but this a minor issue.
The main problem with Java has always been its build tools. They’ve consistently been bad and continue to be. Even today, creating a bundled application with a stripped down JDK with jlink and jpackage is incredibly painful. You’ll need extensive knowledge of the Java CLI, modules, build tool plugins, or tools like Mill which simplify using jlink and jpackage, but even then it remains complex and frequently fails. In reality it should be as simple as something like "java package". Even these days, I frequently see Java developers presenting their desktop apps on Reddit and if you look at how they deploy them, it's often a fat JAR because they struggle to use jlink and jpackage effectively. Ironically, even generateing a fat JAR can be challenging.
As someone who has spent over two decades developing desktop applications including witnessing the shift to horrendous Electron firsthand I can tell you that this was a primary reason Java basically vanished from being so prevalent on desktops. Inexperienced developers often struggled to deploy even simple Java applications, grappling with either runtime incompatibilities (Ironically, developers are somewhat reintroducing the same problem with WebView-based applications) or having to tell their users how to launch a Java app. While some claim desktop apps are dead – which is nonsense – the same applies to CLI applications. CLI apps remain prevalent, primarily written in native languages or Golang, sometimes even Node or one of its derivatives. Rarely Java for the reasons I just mentioned and don't get me started with Graal Native. If someone decides to write a simple trivial CLI app in Golang, they'll simply build it with a single command and be done with it. With Graal Native, you'll have to go through using the tracing agent, and if you're lucky you'll have a fat native executable after minutes of compile time. Forget Graal for a minute though. Java would already go a long way if bundling your application with a stripped down JDK (jlink) was as easy as typing in a single command without having to deal with complicated Maven or Gradle plugins.
TIL Mill, I've been in build hell trying to package a javafx GUI gradle project that depends on a non-module-ified lib (usb4java, long story, no I can't use anything else). Beryx/badass failed entirely, was able to get something working with Gradle doing jlink and manual CLI jpackage ...
But tbh the whole experience makes me distrust the Java ecosystem if you're supporting anything that is slightly out of the community's view or priorities. Even JavaFX shows very patchy support for certain very standard UI concepts, and the situation with packaging is bad as you say.
Anyway, is mill worth switching away from Gradle? (Does mill integrate at all with idea?)
Mill does work with idea (via the build server protocol), and the ideas behind it are very sound (a build tool is basically a function calling other functions - on which they depend. You just want to parallelize their running and cache their results.
But it does have a learning curve and you may sometimes end up having strange error messages. (As an implementation, it's basically Scala macros turning normal looking scala functions into a static task graph). It is getting better and better support for mainstream java build setups, and it's possibly the best tool for something very custom. In between the two extremes, you may or may not have a better time with Gradle/Maven.
I feel like Gradle is only relevant for Android. All other projects are fine with Maven (and I like a lot that Maven doesn't allow to code in the build config, any complex logic should be extracted to a custom build plugin, using real code. I just have PTSD after some build.gradle monstrosities).
It's just that Maven doesn't have a good core abstraction and it is not a reliable build system. Like even with base plugins, let alone with additional ones you can't be sure that a build actually picked up every change, you often have to do a double take and do a clean install instead to get some stale files cleared. This should never happen in a build tool and every other feature is secondary to this error.
That's why I defaulted to Gradle, which has its own idiocities (like tending to break the syntax on every second major version, but it's much better with the kotlin DSL), which at least 100% sound.
For more experimental/hobby projects I choose mill though.
JEP 504: Remove the Applet API
Glad to see this being removed. Java plugins especially on Linux were awful and required by tons of corporate stuff. Anyone remeber IcedTea Web? A functional and opensource Java plugin and Java Webstart implementation?
Note that the the Java plugin and webstart was removed a long time ago.
I personally regret that the API was removed as it's a few classes and they are still used. Just search JApplet on Github. It's also possible to run applets in the modern browsers with WASM or in Java IDE's as plugin.
Remember IcedTea Web? Oh boy, I still have environments that use it.
I made several Webstart corporate apps back in the day! The infrastructure was pretty neat, when it worked. And it was a whole lot better than JS back then, still in the IE6 times.
Yeah XMLHttpRequest and activex thing IE6 had. That was Javascript style that days.
I was pretty surprised when I learned recently that the Java alternative for green threads doesn't use colored functions. It put Java in a higher place in my perception.
It doesn't completely solve function coloring though. Causing carrier threads to get pinned is still not good, similarly as calling blocking function from async function is not good in colored systems.
There are not a lot of cases left that still cause pinning. FFI is the main one.
What are colored functions?
Any time you have a barrier between one function being able to call another. The original article on this called them red functions and green functions. A green function can call a red function but a red function can't call a green function.
In terms of async, it's when you have to have a function with "async" attached to it and making it so that only other async functions can call async functions.
It ends up creating a weird circumstance where you can end up with a lot of duplicated APIs, particularly in libraries, because you are providing both async and non-async versions of functions.
The coloring is a property of concurrency safety and whether the language enforces it.
For instance, if you resolve a future in the wrong context you'll still have problems - the coloring is just a compile time error that you are doing things wrong, rather than a runtime deadlock.
Right, and a lot of people would rather avoid that issue altogether by using a different concurrency model.
The term comes from an old blog post [0] about different kinds of effect systems. Every function has a color, and every colored function can only call functions that are compatible with it, usually of the same color. The net result is that you end up either duplicating a lot of your common code so you have compatible interfaces for all the different colors (let's call that "separate but equal" if we're feeling spicy), or you end up shoving round pegs into the square holes of your dominant function color.
[0] https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...
https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...
The terminology is used to talk about languages that have async and sync functions where you declare (or color) the function as either async or sync.
In these languages it's pretty common for the language to enforce a constraint that async functions can only call other async functions. Javascript / Typescript, Python are popular examples of languages with colored functions.
https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...
In this context: functions anotated with async
[flagged]
Please don't fulminate on HN. The guidelines make it clear we're trying for something better here. https://news.ycombinator.com/newsguidelines.html
[flagged]
No, it refers to a function that has constraints on how it can be called and composed. A classic example is functions tagged `async` in languages like Javascript or Rust.
(Technically, that's the symptom - the underlying cause is that it's a function that involves some effect, like asynchronicity, or, in some functional languages, IO.)
No.
No need of colored functions because that Java green thread returns a Future<Value> not Value like colored functions
That sounds just like promises in JS which most definitely are a function color.
"green threads" is generally how I see these systems identify as "non-colored but with async-like performance" fwiw. or "fibers". otherwise it's "async" or "coroutines".
There are different types of coroutines. The C++ type are sometimes called "stackless coroutines". With stackless coroutines you can't yield from a nested function call. Stackless coroutines are basically generators where you can pass arguments through resume, and async/await is effectively a form of stackless coroutines with yield/resume semantics that aren't fully generalized as coroutines, but oriented toward some bespoke notion of concurrency rather than as an abstract control flow operator.
"Stackful coroutines" allow yielding from any arbitrary point. They're basically fibers, except with the explicit control transfer and value passing yield and resume operators; there's no hidden or implicit control transfer like with green threads. Though, some people would argue allowing any function to yield without announcing this in their type signature is tantamount to hidden control transfer. Personally, I don't see how that's different than allowing any function to call other functions, or to loop, but in any event languages are free to layer on additional typing constraints--constraints that can be tailored to the desired typing semantics, rather than dictated by implementation details.
Stackless coroutines are typically implemented as a special kind of function whose state is allocated and instantiated by the caller. In contrast, stackful coroutines are typically implemented by reifying the stack, similar to threads. The "stack" may or not be the same as the system's ABI stack.
In stackful coroutines, unless there are additional typing constraints imposed by the language for hygiene reasons, any function can typically be called as a coroutine or use yield and resume. There's no need to compile functions into special alternative forms as call frame management works the same whether invoked from a coroutine context or not.
Are you perhaps confusing green threads with stackless async models, like async/await? Green threads don't imply colored functions.
They said "Java alternative for green threads" so they're talking about not green threads.
What alternative would they be referring to? Green threads were only (re-)introduced to Java in version 21 in 2023.
I think what they're trying to say is that Java's green thread implementation has special support for async I/O. Threads that block on I/O aren't polled for completion by the runtime, instead they use OS async features under the hood.
This allows Java's green threads to compete performance-wise with async/await solutions, but with cleaner code that doesn't need colored functions.
In older green thread implementations in other languages, I/O can actually cause significant CPU overhead due to polling threads that are blocked by I/O requests.
I have been using Java since version 1.4. Both the language and its ecosystem have come a long way since then. I endured the height of the EJB phase. I adopted Spring when version 1.2 was released. I spent hours fighting with IDEs to run OSGi bundles. I hated building UIs with Swing/AWT, many of which are still in use today and are gradually being replaced by lovely JavaFX. When I look at code I wrote around 12 years ago, I'm amazed at how much I've matured too.
One of the best tools I built was years ago with Swing and Miglayout. Still remember it fondly.
> I hated building UIs with Swing/AWT, many of which are still in use today and are gradually being replaced by lovely JavaFX.
Dude JFX yielded what was called RIAs to JavaScript like almost 15 years ago. Of the three major GUI toolkits Swing, JavaFX, and SWT it was Swing that gained HighDPI support first (10 years ago), and continues to be the base for kick-as IntelliJ IDEA and other Jetbrains IDEs.
Swing was simpler in some ways than JavaFX. I still remember JavaFX treeview taking 3 Generics and I was unable to figure out what one of them is for from the docs. Had to go on Stackoverflow, where someone said it basically didn't matter. But JavaFX looked great at the time.
As someone who has been out of the Java world for many years, but recently forced back into it due to Android dev requirements, Post lawsuit, what is the relationship between Android (Google) and Java now? When can we expect 26 on Android? On that note, why is Android always so far behind? Is it because Kotlin is primary or is it deeper? Did the lawsuit play a role?
Java's primary development happens on OpenJDK.
Android has their own runtime (creatively named as Android runtime), which does not run java byte code, but their own binary format. JVM class files can be compiled to that format, but the support for that always lags behind OpenJDK java versions.
Part of the reason kotlin became the de facto language on the platform was that they supported only terribly old Java at the time, that didn't even have lambdas even though it was already out.
The problem is that most of the Java libraries want to follow the desktop/server, aka the OpenJDK scene, but that would make them incompatible with Android so there was/is some incentives to bump up the version they support.
The new (ish?) Android UI toolkit is only useable from Kotlin and is implemented fully as a compiler plugin. Google has been clear that Kotlin is the Android language now and that's where new features are going.
I've used Java decades ago (anyone remember servlet?) and I'm glad that I can use flutter for Android development.
I do really need to give flutter a try. My only reason I haven't yet is that I have no desire to learn Dart. How do you (or anyone) like Dart compared to Java or Kotlin?
Went from c# to flutter and it was easy.
The new concepts for me were using immutable classes with the keyword "final", and the whole concept of state management in mobile apps because I've mainly done backend.
I've only used kotlin in the android files for flutter but nothing else.
I'm also not totally objective on that because my Java experience is from a long long time ago, my general feeling is that flutter is less bloated than java.
And I don't want to start a culture war on this, because we all know turbo Pascal is the best.
I have way more experience with java on android than Flutter, and Flutter so far has been a breeze.
Kotlin with Compose is a massively nicer experience than Dart/Flutter
Now with KMP you can build a desktop/iOS/Android app with single codebase as well.
Man I still have scars learning Java in college. Took the entire fun out of coding until I ended up learning C.
I haven't read a Java manual since the time of Java 8. Do you have any books or other resources you could recommend to catch up with all that has changed in these years?
You might find those useful:
https://www.marcobehler.com/guides/a-guide-to-java-versions-...
https://advancedweb.hu/a-categorized-list-of-all-java-and-jv...
And this more like a reference:
https://javaalmanac.io/
https://javaevolved.github.io/
A couple of books were helpful to me, both by Venkat Subramaniam and published by Pragmatic Programmers:
- Functional Programming in Java
- Cruising Along With Java (this covers everything else that is "new" other than functional programming)
Really glad to see we're getting a native PEM API.
Pleasantly surprised.
But it is a preview though.
Lazy Constants looked interesting. The impl uses unsafe: https://github.com/openjdk/jdk/blob/master/src/java.base/sha...
All the changes look great. But I don't know how I feel about the syntax. A lot of things that very well could be first-class just aren't. Instead of a `lazy` keyword, we get `LazyConstant<T>`.
I'm sure there's reasons as to why. I just don't know them.
It‘s easier to evolve library code. If Java would ever infer type of constants from initializer (makes more sense than a new keyword), it could look nice and powerful:
Because library code is easier to maintain and for people to understand.
And plus if you add a new keyword someone else will complain about complexity of keywords.
Once introduced, keywords and Java syntax is nearly impossible to change or to remove. If it's possible to get the job done using a class, perhaps with some JVM magic, it's not wise to whip out new syntax.
Seeing as we're having a $LANG war, after 15 years in JVM land, I moved to a Python / Go shop, and fuck I miss Java.
Not so much the language (although modern Java is pretty slick), but the stuff surrounding it.
* No typosquatting issues because every package has a group id verified by real humans and DNS TXT records.
* JMX as a standardized mechanism of exposing ways to interact with running code / expose metrics. (Even if you have to deal with the stupid ass protocol where you have to connect using a DNS identity the JMX server recognizes)
* Logging libraries that give people running the code control over what gets logged and how, not the developers (looking at you Golang, wtf is with your logging approach where devs have to explicitly consider the fact that you might want to run logging at DEBUG and code it into your start up args?)
* The ability (via JMX) to set, at runtime, one particular logger in one class or file to a desired logging level without restarting the application.
* The performance of the JVM.
* The vast FOSS ecosystem.
* Not having to fight C build chains for that one dependency that's using CGo or a Python wrapper around a C lib that no wheel supports for your given tuple of Python version, OS, and architecture.
Honestly, as someone who is a self-taught developer who taught himself in Python, I thought I was coming home to my first love.
Turns out, I really hate the horrible things you can do in Python - looking at you Django, don't be so dynamic your brains fall out - and really dislike the experience of trying to run a Go service compared to a JVM service.
Java and its ecosystem is just good at getting shit done in a predictable manner at both the dev level and ops level.
> * No typosquatting issues because every package has a group id verified by real humans and DNS TXT records.
While I think this is a huge boon, have you ever published a package on the Maven Central repository? I must confess I haven't in a few years now, but when I did until ~3 years ago it was a major pain in the ass. And every release again.
I think there's something to say about Go's model where the package is just in some Git hosting and a release is just creating a tag. As a package maintainer, this is just pure bliss compared to the Maven thing.
> and really dislike the experience of trying to run a Go service compared to a JVM service.
What are you running into specifically? I have the complete opposite experience. With Go, 1 small binary comes out that I can run anywhere (and put into a distroless container), whereas with Java I have to find a way to somehow run a full JVM (most often with (large parts of) an OS too).
Perhaps you're alluding to the things you can do with JMX, but I have never really seen much benefit in that. I found it trivial to add similar functionalities with internal HTTP endpoints easily. But since I don't have much experience in this particular area, probably I'm missing something.
> While I think this is a huge boon, have you ever published a package on the Maven Central repository? I must confess I haven't in a few years now, but when I did until ~3 years ago it was a major pain in the ass. And every release again.
I’m really surprised to read this. It is well-documented process. I regularly publish something there, never had problems. Why was it different for you?
Yeah, publishing a package is a PITA for the precise reasons of maintaining trust in, and the quality of the packages.
That's why you need documentation to publish to Maven central, that's why your package needs to specify its license, GPG checksum etc.
Yep, it's a lot harder than publishing to Pypi or Cargo, but I'm now firmly of the opinion that it's good that it is. The gates between you and publishing a package are there for deliberate reasons.
> Perhaps you're alluding to the things you can do with JMX
Yep, specifically things like "set the logger org.foo.package.Bla to DEBUG while the app is running", without restarting and without having to add an internal HTTP endpoint to be able to accomplish that. It's just there for free, every JVM logging library and metrics library exposes itself via JMX for that same reason - ease of observability, without restarts, without custom code.
E.g., I can access Kafka client metrics via JMX anytime I like. JConsole will even give me pretty graphs.
If I want them in Prometheus, I run the app with a Java agent that takes those MBean metrics and exports them in Prometheus format on an HTTPS endpoint.
I understand you can accomplish much the same with some internal HTTP endpoints, but that presumes they exist.
If you need them, but that microservice hasn't deliberately exposed them, you need to change the code, and then make a new release, which slows down your ability to diagnose what's going on right now.
In Java, every observability library exposes itself via JMX, all you had to do as a sysop was ensure that the JMX port was open.
Also, the ability to easily observe the metrics of the VM itself via JMX so I can see what's going on with GC in a running app without having to explicitly expose that.
If you suspect a memory leak, or something that should be GC-able isn't, or that there's far too many object allocations occurring that's smashing the first gen portion of the heap and causing excessive GC pauses, the instrumentation to investigate it as your app runs is right there, it's baked into the JVM.
That's why I miss it - the JVM was built to be instrumented and observed by the people running it.
I really wish Golang and everyone else would emulate the Java approach to observable metrics as well as the Java approach to logging and packaging.
There's no shame in stealing the good ideas Java had, but no-one seems to, to my frustration.
> My hope is that the first JEPs out of Project Valhalla will be announced later this year
I have heard about Valhalla at least around release of Java 8. That said that site is a solid description of other current and upcoming JEPs.
Do changes to Java itself impact e.g. Clojure? I think it uses many java primitives instead of emitting jvm byte code but I can be wrong.
Some of the standard library stuff could be usable from Clojure and other languages. The jvm level optimizations (garbage collection) should benefit all jvm languages. The language changes are mostly not that relevant unless you program directly in Java.
I use Kotlin myself (after doing Java since 1995). Most of the overview here reads like they are adding a lot of stuff that Kotlin has had for many years. Structured concurrency, lazy stuff, etc. You can argue about which language does it better/nicer/etc. but that debate is a bit boring to me. But good for Java developers that they are getting some obviously useful things that so far they never had. Progress is nice. Better late than never.
Java improvements usually have a runtime component, so no, kotlin simply couldn't have had Lazy no matter what. It was just syntactic sugar for a getter.
"Just syntactic sugar"
That's what most modern programming languages provide. Syntax matters. Kotlin offers a lot of syntactic sugar for things that are a bit verbose in Java.
The new structured concurrency stuff in Java is actually a great example of that. More or less does the same thing, Kotlin manages to do it with a nice Kotlin DSL. Java does it with a lot of builders and function chaining. Which is a lot less readable.
In the end, Java caught up and you can now use this for more complex concurrent/parallel code (both should be possible with this, like it is with co-routines in Kotlin). Which is a good thing.
Didn't mean to say that syntactic sugar is bad. But when Java touches a language feature they prefer doing it only when absolutely necessary and even then having the biggest part be in the runtime if possible. E.g. in the lazy case, it's backed by runtime optimizations, they are treated as proper constants. A fancy getter over a lambda is not the same thing, and that's all syntactic sugar in this case would give you.
Sometimes, yes. E.g. if the value types stuff ever gets implemented, that will be very useful for other JVM languages. OTOH some changes are purely syntax sugar in Java itself (e.g. allowing multiline string literals) and those of course don't affect any other JVM language.
Yes, kind of... for instance you can use Virtual Threads now from Clojure:
https://clojure.org/news/2026/03/11/async_virtual_threads
I'm pretty sure all of Clojure runs on Java 8, so if you use some new feature I'm guessing you need to provide a fallback - but you're also going to be running on Javascript and other platforms, so that's par for the course
In general, some java language changes do involve JVM changes.
So yes, it impacts other jvm languages like Closure.
Here most obvious would be GC improvements.
I wonder what percentage of java code in the world is still java 8, and always will be?
Still a lot, but in absolute terms the majority of Java applications are 8+ for 4-5 years now, according to Oracle's statistics - so they are a minority. It's just that there are so many java projects that it is still a huge number.
Vector API (Eleventh Incubator) - maybe 11th time’s the charm.
When it was about the 7th incubator iteration, I got curious so I read the actual JEP history, and it had this informative tidbit, also included in the latest release:
"The Vector API will incubate until necessary features of Project Valhalla become available as preview features. At that time, we will adapt the Vector API and its implementation to use them and then promote the Vector API from incubation to preview."
Project Valhalla has been "in progress" for at least a decade now (Wikipedia say 2014). So who knows when we'll actually see a Vector API in preview.
They made the problem complexity of Valhalla ~10,000x harder by very strict backward compatibility needs. Project Valhalla can take many human generations and multi-billion man years to finish as a consequence.
On the other hand, there is a bunch of movement on Valhalla side nowadays. You can download a build and try out value types yourself!
[dead]
[flagged]
[flagged]
Dont you have parents to tell them that? Open a pr in the codebase
[flagged]
Cool. I feel as though I'll never be able to escape 8, or ignore Ellison's legacy, unfortunately.
> or ignore Ellison's legacy, unfortunately.
Can you elaborate?
Ah , Java, a language I pray I never have to ever touch again.
Too little, too late. Followers.
Android as always in shambles. Shame that neither Google, nor ecosystem cares about Java because they’ve bought JetBrains kopium.
Google basically played a J++ with Android Java, with Kotlin as their .NET/C#.
At least they are forced to partially update Android Java, now Java 17 subset, so that Kotlin can keep up with was is mostly deployed at Maven Central.
Pretty sure they did a J# ;). But I agree that Kotlin is their C#.
The JDK and JVM has advanced so fast while android has been lagging. It's pretty frustrating, especially because google has been so slow to pull in changes from later java versions.
A part of me wishes that android would just dump their hokey dalvik, ART, and other BS and just use the OpenJDK or a fork of the OpenJDK with whatever special sauce they need. A lot of the project Leyden stuff lends itself nicely to maybe someday being able to run real java on android.
Edit: Apparently android is forking OpenJDK, since Android 7.
https://en.wikipedia.org/wiki/Android_Nougat
J++ predates C#. It was Microsoft's version of Java that wasn't quite compatible.
Correct, and J# was a brief transition language to help migrate Visual J++ applications onto the .Net SDK. J++ -> J# -> C# was the evolution.
I say J# is a more apt comparison because like Microsoft's Java, android has a substantial set of APIs that aren't part of the JDK standard. Working on Java vs Anrdoid is practically like working with the JDK vs .Net.
J++ already had those extensions, hence the lawsuit.
Do you think it's legal reasons, technical reasons, NIH syndrome, or some other reason why Android doesn't use OpenJDK?
A little bit of all of the above.
Android's usage of Java started right as Sun was being acquired by oracle and right before the jdk was GPLed.
... And I'll be. Apparently Android is using the OpenJDK since Android 7. [1]
[1] https://en.wikipedia.org/wiki/Android_Nougat
It isn't, check Gerrit commit history, they only take bits and pieces, plus ART doesn't do all bytecode equivalents. Some JVM bytecode don't have counterparts in Dex, rather get desugared into multiple instructions.
Was ART better at the time they wrote it? Do you know if there were any reasons other than perhaps legal, that caused them to go that route?
J# was the transition product to port J++ into .NET, I am quite sure.
Not only I was there on those years, my employer was a MSFT partner that got to test .NET before it was announced to the world, so that we could have our products as part of the announcement event in Portugal.
OpenJDK is cherry picked, Google only picks pieces of it, rather than full compatibility.
No idea what you are talking about. Google internally has a massive amount of code based on JDK 21, and the (amazing and completely transparent move) to JDK 25 is nearly complete.
That's the full OpenJDK @ Google, and it has been for a very long time.
I am talking about fu..... Android!
That's a proper late 90s reference, props!
> Google basically played a J++ with Android Java
No, they didn't. Google happily used regular Java until Oracle played Oracle. Then Google stopped updating the supported Java language version and started diversifying away from Java.
They definitely did not, it was Android Java from day one, and Oracle should have crushed them like Sun did to Microsoft, unfortunately Google was the geek darling of do not evil, thus they got a pass from fanboys.
Oracle's Java Mobile Edition could've crushed Android. No one stopped them.
> Google was the geek darling of do not evil, thus they got a pass from fanboys.
Oracle's case against Google went all the way up to Supreme Court of US. Oracle did not win anything substantial in courts against Google is not fanboys' doing.
Yes they did, although judge say despite Google's wrongdoing, fair use clause would apply.
Additionally to this day it is hit and miss to port standard Java code into Android unless you are lucky with the APIs being used.
Android was not 100% compatible with Java, but mostly because it had a specialized environment. It did not support things like dynamic bytecode generation, but it faithfully reproduced pretty much everything else that made sense.
And yeah, it would have been so much better with Oracle(tm)(r)(c)(fuckyou) running Android with Pure Java(tm)(r)(c)(screwyou) instead. Now with EJB5 and more XML!
You might be too young to remember, but SunOracle essentially abandoned the Java language development for more than a decade, until Kotlin provided a very much needed magic kick.
Oh, and if you think _Google_ is bad for splitting the Java ecosystem, let me introduce you to J2ME and JavaCard.
My dear I am programming since 1986, and a Nokia alumni.
What a clusterfuck this still is. I’m glad I haven’t written a LOC in this brittle eco system.
I wouldn’t blame Google for Oracle being a lawnmower.
I think Java became popular because of Sun. My experience with Java-based apps is bad. Laggy, resource-heavy, IDE bound, and it causes premature hardware performance degradation.
Modern Java is pretty succinct and expressive and I enjoy working with it. Like any long-lived project, Java has its quirks and baggage but you can let go of that baggage if you want. The ecosystem is evolving nicely with new features and it is quite pleasant to work with these days. I’m looking forward to migrate apps at work to 26.