I’ve basically forgotten about Java. It would never occur to me to start a new project in it. Am I the only one? It feels like I’d reach for python if I want fast development and flexibility, Go if I want to handle a bunch of I/O concurrency in a garbage collected way, Swift if I want a nice language that’s compiled and balanced, or Rust if I want performance and safety in a compiled language. Those are just my personal leanings. I know kotlin has made Java more ergonomic, and yet….
You're not the only one I'm sure, but sounds like you don't need it. Its major strengths are:
• Bottomless resource of developers with Java experience
• Vast array of existing libraries many of which are enterprise focused
• Managing very large codebases with many contributors is straightforward
• Standard VM that's very solid (decades of development), reasonably fast, and supported on essentially all platforms.
It doesn't have quite the stranglehold (even in Enterprise) that it had in perhaps the early 2000s and it's the archetypical "blub" language, but it's a perfectly reasonable language to choose if you're expecting Enterprise scale and pure performance is less valuable to you than scaling out with large numbers of developers.
I like Rust, but it's Java that puts bread on my table.
I fully agree with you about the solidity of the VM. The others I am not so sure about.
> Bottomless resources of developers with Java experience.
With Java experience, but what fraction have a systems outlook? What fraction have an experience with other languages to ensure that the code they write is simple and understandable and direct? My own experience is that too many come out addled by Enterprise Java idioms, and when you actually write some code in Erlang or Go you realize systems aren't as complicated as they have been made out to be.
> Managing very large codebases ...
I wonder if this is self-fulfilling. My theory is that these codebases are huge because their designs are enterprisey. The primary drivers of complexity are indirection: factories, dependency injection, microservices, these are all part of the same malaise.
> With Java experience, but what fraction have a systems outlook?
It depends what you mean by systems outlook but JVM based code is pretty common (to the point I’d say ubiquitous) in large distributed systems.
In open source it’s much the same. Many of the large Apache projects are in JVM languages, for example.
> The primary drivers of complexity are indirection: factories, dependency injection, microservices, these are all part of the same malaise
The indirection in Java does drive me crazy. But dependency injection is a problem to solve in every language and libraries that can do code generation at compile time like Dagger2 make this predictable, debuggable, and fairly easy to reason about on the JVM.
Microservices are, in my opinion, more of a business organization solution than one tied to any specific language. If you haven’t read Steve Yegge’s blog post about Amazon vs Google I think it’s good reading on why/when SoA is a good idea.
There are more Java devs out there than people living in my country. I don't think generalizing this way is helpful, there are many different styles of Java development, and developers have vastly different skill sets.
In addition to other answers: Java absolutely does have the qualities necessary for startups, so using it for new projects makes sense.
1. Modern frameworks and AI assistance can help ramping up a decent backend in days. Solo tech co-founder needs to know only Java or Kotlin and some frontend stack to build MVP quickly and will spend such amount of time on non-coding tasks where language features will be irrelevant. Swift can be the second language if you go mobile-native.
2. Scaling isn’t the problem you are going to have for quite a while. It is quite likely, that problem of scaling the team will come first and any performance bottlenecks will be noticeable much later. Java is good for large teams.
That said, from business perspective, if you want larger talent pool, fast delivery cycles and something that may remain as your core stack in the long term - Java or Kotlin is probably the best choice. If you want fancy tech as a perk to attract certain cohort of developers or you have that rare business case, you can choose Go or Rust. Python is popular in academia and bootcamps, but TBH I struggle to see the business value of it for generic backends.
Java is better than Go on every count, and almost all of your cases are 90% done by Java, so it's quite clearly a very good choice for almost everything.
I think it's not just you, but certainly not everyone. Kotlin with Java 21+ is my go-to choice for an I/O-bound service, or really any service. It's just so ergonomic, and with virtual threads the code can be as simple and efficient as Go - while also taking advantage of possibly the best and largest library ecosystem in the world.
I'm not knocking Go or Python - if those are your preferred tools, they're more than adequate. Java, however, isn't nearly as irrelevant as you may perceive.
I mean, I share your opinion personally but plenty of people find it pleasant to read and write. If it was really a bad language, it wouldn't have the adoption it does.
It's an interesting parallel development that people are complaining about the bad original language on both JS and JVM platforms and often using other languages (Kotlin, TypeScript, Clojure/ClojureScript, etc). I guess even Swift instead of Objective-C on the Apple side counts here in a way.
What I find sad in some of the guest languages communities, like Kotlin and Scala ones, is how so many happen to disdain the platform that makes their ecosystem possible in first place.
No one is going to rewrite the JVM, even though there are several implementations, all of them are a mix of C, C++, Assembly and Java, zero Kotlin and Scala.
Yet as usual there is this little island of Kotlin or Scala ecosystem, with their own replacement of everything, and continuous talks how it is possible that the platform that makes their existence possible hasn't been rewriten into them.
Typescript and Clojure folks are traditionally more welcoming of the platform, they rather appreciate the symbiotic relationship with the host, and much more fun to hang around with.
Are you the reason I got downvoted? I was very surprised by that.
I’ve spent years writing Java and later Scala, in academia and later production. I’ve always followed to see how the JVM and the language/ecosystem has progressed. And now I don’t use it at all. Is it really that odd to take a temperature on a site filled with other tech folks? I don’t understand why you took it so negatively and use words like bloviate, or attack me as just posturing to look cool (how does one look cool on a geeky Internet forum?). One of the HN tenants is to “converse curiously,” which is exactly my mindset when I wrote my comment. And if you look at the other replies, it seems others took it that way as well with healthy discussion.
Your comment is generic off-topic that has only Java in common with original post. The way it is written, it gives certain vibes and doesn’t sound like genuine invitation to compare Java with other technologies. If that was your intention, maybe you should write your own post and ask there instead.
I don't understand the downvotes, I don't find your post offensive. My guess is that people don't downvote to moderate, but rather to show that they disagree. Which unfortunately kills the discussion a bit.
I like Java (but I love Kotlin), and it seems like work on the JVM is more active than ever. I can understand your preferences, but what I observe e.g. with Desktop apps is that people use Javascript and embed a whole browser with it (e.g. ElectronJS). I would always prefer a JVM desktop app. Also with modern UI frameworks (including e.g. Compose), I am really hoping that the JVM will get a boost for Desktop apps.
I absolutely downvoted to moderate - the post had nothing to do with the article on hand. It's much more appropriate for an Ask HN post.
It's really tiring to see these "Oh this language sucks" posts under articles that discuss details and techniques in languages - it added nothing useful to the conversation, especially since it was framed as a personal preference. Who cares that you don't care about Java?
It was framed as a personal factoid (used to use Java, now don’t), followed up by a question for everyone else: “Am I the only one?”And that’s why there’s healthy discussion to my comment if you look at the replies. I think it added quite a lot if you read it all. All of these quirks add up to a meta comment on the language.
But it did not say "this language sucks". To me it was kind of asking something like "is Java still relevant nowadays?", in a polite way. It actually got a few interesting answers ("Java sucks" probably wouldn't).
I believe that it's enough to not upvote a message if you find it irrelevant. The upvoted messages will stay at the top. It is not completely off-topic: the people who will read the featured article have knowledge about Java, after all.
My concern is just that downvoting is fairly aggressive. You don't need to be massively downvoted many times to effectively end up being silenced (if you are moderated 2-3 times while you wrote a polite, genuine question, chances are that you won't come back). By aggressively downvoting everything that we don't find particularly relevant, I feel like it just encourages bubbles. "We are a group of Java enthusiast, just don't come talk to us if you are not a Java enthusiast yourself. Find a group of people who has the same preferences as you do instead".
I also don't understand the downvotes; the original post was polite and
informative, the "moderator" throwing downvotes was aggressive, and more
harm was done than help.
I have the upvote counters hidden, because I don't want to see some
misguided individual to influence what should be important for me, and
what shouldn't. I make my own filtering choices.
I wish that one day the internet will realize that upvote counters are
more harmful than they are useful, just as it realized for downvotes.
Upvotes in general promote bubbles.
I would like to note the irony: my comment above is being downvoted as well :D. It is starting to feel like the kind of toxicity I find on StackOverflow.
They seem to disagree :) Given I was polite, curious, and not leaving a “throwaway comment” that was on the broader topic (let alone the numerous substantive replies), it’s giving zealotry to me. Oh well.
Probably not. Java had stagnated for quite a while, entirely missing the lightweight threading and/or async/await revolution of the last decade. The JVM ergonomics also just sucks, a lot of apps _still_ have to use -Xmx switches to allocate the RAM, as if we're still using a freaking Macintosh System 6!
On the other hand, it's a very mature ecosystem with plenty of established battle-tested libraries.
I think your information is outdated. Java has had lightweight threads for several releases now. It also has type pattern matching switches, and a bunch of modern ergonomics.
async/await is not really a revolution, so much as a bandaid bringing a modicum of parallelism to certain programming languages that don't have a good threading model.
Xmx is mostly a thing if you have very small RAM, or some sort of grievously misconfigured container setup. By default it grow up to 25% of the system RAM, which is a relatively sane default.
> I think your information is outdated. Java has had lightweight threads for several releases now.
Well, yes. It was released as a part of JDK 21 a year ago. So far, the adoption has been spotty. They are also implemented not in the best possible way.
> Xmx is mostly a thing if you have very small RAM, or some sort of grievously misconfigured container setup. By default it grow up to 25% of the system RAM, which is a relatively sane default.
Other more sane runtimes (like Go) do not even have developers care about the heap sizing. It just works.
It’s valid criticism because you do need to think about it less in other runtimes, but it doesn’t always just work. There’s a reason why GOMEMLIMIT and other knobs for high allocation programs were introduced.
IIRC .NET just sets it to 75% of available memory.
> IIRC .NET just sets it to 75% of available memory.
Out of all three Go one is the least configurable. .NET GC is host-memory aware and adjusts heap size automatically. It does not need Xmx as it targets to keep host memory pressure low but the hard limit really is only available memory unless you override it with configuration.
It has been further improved as of recently to dynamically scale heap size based on allocation rate, GC % time and throughput targets to further reduce sustained heap size.
Java does the sane thing within containers, and you definitely not have to set memory settings anywhere else, unless you want some very specific behavior.
I thought this was the case but actually couldn’t find any documentation on it. The best I could find was that the vm is aware it is in a container and will correctly set the heap %’s based on the containers memory. It still looked like it was defaulting to 25%.
The async/await is not a revolution, but rather is a tool only for
specific use cases. It shouldn't be used by default, as it makes the
project unnecessarily complicated. If your requirements are to do heavy
parallelism where everything uses I/O, then use async, but for the rest
of cases? Probably not worth it.
> ...entirely missing the lightweight threading...
They deliberately took the longer route, aiming to integrate lightweight threads in a way that doesn't force developers to change their existing programming model. No need for callbacks, futures, coroutines, async/await, whatever. This required a massive effort under the hood and rework to many core APIs. Even code compiled with decade old Java versions can run on virtual threads and benefit, without any refactoring or recompilation.
> ...and/or async/await revolution of the last decade
async/await is largely syntactic sugar. Java has had the core building blocks for asynchronous programming for years, with CompletableFuture (2014, replacing the less flexible Future introduced in 2004) and NIO.2 (2011, building on the original NIO from 2002) for non-blocking I/O, along with numerous mature libraries that have been developed on top of them over time.
That’s in the works, where it adapts from 16mb to terabyte heaps. The current GCs have a max, with lazy allocation and ability to release back to the system periodically, but are not as system aware.