Like many others, I started with C. It taught me the basics - memory, pointers, writing data structures from scratch - but most of the time it felt like I was just trying not to break things. Solving problems became more about handling the language than understanding the logic.
Then I came across Java, and something just clicked. It felt structured, readable, and intentional. Almost like reading good English. For the first time, I could focus on the actual problem instead of building the tools to solve it. Collections, built-in libraries, and a reliable runtime made coding feel productive, not just painful.
Even now, years later, Java still feels like home. It’s not perfect, but it gave me the space to learn, grow, and build things that last. I really appreciated this article - it captures that quiet strength Java has, and the care so many people have put into making it better over time. It reminded me why I still enjoy writing Java after all these years.
Working under it, apart from usual initial pains was marvelous - the language itself somehow forced me to make much cleaner code compared to C, which as a beginner became horrible mess pretty quickly. Suffice to say, debugging was trivial, no pointers just easy life.
25 years later, Its close to 100% of all work I ever done professionally and I don't mind surfing that wave till retirement, Java is so spread into corporate sphere that there will be enough work especially for seasoned experts for decades to come.
Stuff juniors often complain - OO bloat, EE megabloat etc become invisible pretty quickly, and you just work with the code, however you like it. Its a great platform to see that premature optimization is really not something to worry about during initial implementation (unless you do N-th rewrite of some performance-critical app, which most of us rarely if ever do). It doesn't mean any spaghetti code is fine, just that following normal design principles is normally good enough and one can focus on things like security, clustering and actual features.
Design patterns are optional, but are applicable across languages. Their purpose is to communicate effectively.
Important to remember none of that is part of Java.
There was a period of time (and it goes in waves) when extreme complexity was the thing, and one peak of this mania coincided with the rise of Java, so a lot of people on this high horse of complexity latched on to Java because it was the place to be.
None of that is related to the language Java though, nor its fault! I've been writing java since 1996 (including many years at Sun) and not once have I worked on those silly MethodHelperContainerParameterEventPrincipalGetterBean-style codebases.
That's purely a choice and one best avoided. Just use java as a very fast very scalable memory-safe language, keep the code simple.
(class name courtesy of https://projects.haykranen.nl/java/)
It had abstractions but you were never forced to use them. Ditto with design patterns - you could use them, but none were forced, unless you _had_ to use a framework (like spring), but that's a choice! May be it wasn't your choice, but it was a choice someone made.
If you used java like you used C, java is much easier and less mentally demanding, and therefore less prone to mistakes.
You focus on algorithms and solving problems instead of fighting with language, building systems, linker errors, solved problems being annoying, etc
In general the joke is real:
How much c# is faster than cpp?
By a few months at least
I've worked with Java for 25 years and have a love/hate relationship.
Java garbage collection is both great, and terrible. Sometimes objects are instantiated in a method, and should be marked for GC when you leave the method but aren't. There isn't logic or reason, and it trips up juniors hard and reworking "new" features like streams into basic for loops fixes it, even though there isn't any really good reason why.
When it works first time you never even need to think about it, and its awesome. When it doesn't, there is no escape hatch to fix it. Its probably for the best, I would probably prefer someone switched a stream to a loop to fix a GC bug than to keep the stream and add additional code for flagging objects.
In the last decade of writing Java software I didn't ever come across a genuine GC bug where a unreferenced object wasn't collected. I'm not disputing that they exist, but if you regularly hit such "bugs" I'm wondering if your understanding of Java GC might be flawed.
Do you expect objects to be immediately collected when they are not reachable anymore?
Can you give more details, and/or an example?
"This wasn’t just about type safety – it was about reducing the mental burden of programming."
The "x wasn't just about n — it was about m" carry a strong LLM smell.
> Whether you’re debugging your first NullPointerException or architecting enterprise systems, there’s always someone willing to help you grow.
> Whether you’re starting your programming journey or looking to add a robust, reliable language to your toolkit, Java remains one of the best investments you can make in your technical future.
I wish people would be more thoughtful about how they used LLMs.
AIs train on all the text of all the web (that they can get, at least). A lot of that text is "corporate voice" (that is, written by nobody). But even the rest, the AI blends it all together. As a result, in the output, there's no voice - or rather, all the voices all blended together, which doesn't sound like anybody.
> Java has been my companion through:
> Learning object-oriented programming > Building enterprise applications > Navigating the transition to cloud computing > Exploring microservices and distributed systems > Mentoring other developers > Speaking at international conferences
Yeah this is literally what 90% of senior programmers have done regardless their favorite languages. Either AI-slop or human-slop.
I really want to like Java, or JVM-based languages specifically, but its extremely annoying and complicated to figure out how and why thing works.
Java has Maven and Gradle that serve as package managers. I'd say they are not any more complex than npm, except if you need complexity to do something very specific.
and i do argue that maven has the complexity correctly silo'ed - you need to write a maven plugin to do anything complex and custom, and fit that plugin into the maven ecosystem/api/framework (however deep you need to go).
As opposed to the 'normal' Makefile style build, where you add instructions and scripts (which i think both Ant and gradle inherited the idea from, and thus neither really makes for better builds imho).
https://en.wikipedia.org/wiki/Excelsior_JET
https://en.wikipedia.org/wiki/GNU_Compiler_for_Java
https://www.aicas.com/products-services/jamaicavm/
https://www.ptc.com/en/products/developer-tools/perc
The difference being that those projects required $$$$ that only big corps were willing to shell out.
Now you get free beer via GraalVM (evolution from MaximeVM efforts at Sun Labs), and OpenJ9, IBM's AOT compiler that traces back to Maestro realtime JVM for embedded development.
So complaining about $$$$ in AOT toolchains is no longer a reason.
Then we have the Android cousin that does a mix of JIT and AOT since Android 7.
No, it isn't. `go build` is a single binary.
Seriously? This XML reminds me of the issues that I had when I first started Java, what the hell does any of these mean (yes, yes, RTFM) but then I could also just use another language and be done with it?
Things missing in Java:
- .? operator
- operator overloading
And there were a lot more, but most of them are already solved. The language is tidy and usable, the Optional api is not bad, the native function calling is improving.But what I wanted really say is: the language itself is one thing, but the libraries available are the other. The strongest libraries in Java are the part of the language, especially time handling, character encoding, etc. Java was built with utf-16 in mind and other languages are still trying to cope with it. There are frameworks (outside the language standard) which allow crazy fast web service and DB development. It's all good, it's all standard and it's rarely breaking the backward compatibility. So you get a new developer, just after CS Bachelor and they jump into the project and understand the huge part of it.
When I'm learning new languages, I tend to try writing business applications and usually I cope with the same problems: datetime, string encoding, database connecting, etc. Yeah, golang has great goroutines, but they still import web service library from some guy's github, which can vanish in no time.
stream on collections (the local functional implementation of map/reduce/…),
interfaces everywhere,
and more importantly safe function extraction by your favorite IDE.
Let me elaborate the last one: you write an horribly long spaghetti code (because you are a junior, or you are in a hurry). That’s ok because the “Extract method” instant feature of your IDE will help you safely extract each piece of code AFTERWARDS into its own small function (that can be tested in isolation, where local variables stays internal to the function, where the interface contract in term of input/output/sideEffect is clear, where the function naming is meaningful).
The IDE can even tell you that this code you are extracting as a function appears at several other locations that should also be replaced with a call to that new function.
I don’t know if Typescript support in IDEs reaches the same level of simplicity/safety in term of function extraction.
But that feature is absolutely critical to go from spaghetti code to clean modular code, when you are a junior/work with juniors.
I'd say Java is a great production language, mostly because it's so simple that I don't need to "learn" it (when you know better than using madness like `==` or Serializable).
However Java has advantages too: the IDE support was miles better than Scala, build times were shorter, most frameworks were more mature and better supported and the language itself was much more stable.
There's beauty in simplicity, and Scala is the antithesis of that, it has not only the kitchen sink but the whole kitchen and some house attachments within it. I fell in love with Scala for a while, worked with it for a couple years, and absolutely hated it whenever I had to train someone new. Nowadays I simply refuse to work with it because I'm not willing to relearn all the stuff it needs to be productive.
The thing is that, equality is the difficult problem. "equals" in JVM languages has a lot of problems. Dynamic languages are much more horrible in this aspect. JavaScript `==` is much worse than Java. Python is guilty too in my view, for using `__eq__` method. The only language I know which solves the problem correctly is Haskell. (Or, `Eq` in Cats)
our world literally runs on the JVM.
however - the "Java" ecosystem used to suffer from architecture astronauts & complexity merchants. Certain things like Quarkus & SpringBoot have helped reduce that.
if you keep Java simple, don't ingest too much OOP Kool-aid. You can literally make anything that will work today, 10 years from now, 20 years from now. that's reliability you won't get from Python, Ruby & Javascript.
Remember the JVM offers alternatives - Clojure, Kotlin. with a Kotlin a nice compromise.
Learning Java before C is like learning to ride a bicycle before you learn to walk. You will need to learn C eventually, but learning C once you already have a high level language under your belt will make the experience frustrating. Having to manage your own memory, build your own data structures, it can be fun, but it's less fun once your brain is already wired to expect these things to be done for you.
As a result it's more honest to use a language where it doesn't feel as though you're touching the bare metal, because you aren't anyway†
When I last checked both Oxford and Cambridge teach an ML as First Language. So did the place where I did my degree decades ago although today it teaches Python (which I believe is a mistake). That's because the theory of computation is foundational here, not the practice.
† Even assembler isn't touching the bare metal, you have features like out-of-order execution and register renaming between the machine code you wrote and the actual things done.
Quite a bold assertion. I learned C in university—and while I am sure it was beneficial to my development as a programmer—there have been exactly 0 times since then that I have needed to read or write C.
That’s just my anecdotal experience, but I’d reckon many people can have a very successful professional career while never having touched C.
Whole careers have been built on producing CRUD web applications with Java on the backend and Angular on the frontend.
It's not exciting, but so is life without income in countries where this line of work is something to aspire to. I should know, as I live in such a country.
There are, of course, other certain people and their even bigger egos already in this space, but it's enough to avoid the training/certification treadmill to not have to deal with them.
Point being it's good that a hammer is a hammer and its best that no one tries to reinvent it. I don't care how cool my hammer is as I'm not excited to drive nails into planks.
Java is an alright language by itself, but the "EE" frameworks and the ecosystem that surrounds them are corrosive to good software. You are actively harming your brain by learning JavaEE. If you do that to new developers you deserve to have your beans turn undiscoverable on Christmas Eve.
Frameworks like Spring are absolutely essential for many kinds of business software. Sure, there are slightly more focused alternatives like Micronaut (and Quarkus for that matter), but they tend to have more specific use cases.
In practice, teams that try to write real-world business systems without such frameworks end up with a spaghettified mess that just illustrates a variation of Greenspun's 10th rule: Any sufficiently complicated Java program without a framework contains an ad hoc, informally-specified, bug-ridden, slow implementation of one-tenth of Spring.
I have been dealing with "EE" frameworks since C was the main enterprise language, or even xBASE.
Because OOP hype frameworks, we had Yourdon Systems Method and nice overblown frameworks written in C, with OS IPC all over the place, aka microservices.
TLDR: don't use XML.
Please note that Java is not human friendly. You can learn it for years and still shoot your leg easily.
Would prefer to use Kotlin or Clojure.
Java had changing its skin: Applets and Security managers, part of the cornerstone of Java 1.102 are gone. So Java are 2-3 different evolving language nowadays.
JVM has so strong optimization layers which make very difficult for other languages to provide similar performance (Erlang is one of them in my humble opinion).
Yeah C/C++ program are faster but error prone (manual memory allocation...) PHP is faster for web developing but refactoring is a nightmare. Python can compete, but I do see few big projects written in it (Zulip,Dropbox,Plone/Zope).
JavaScript is super rapid dev rapid but can become a mess.
Rust is the newcome, I do not know but it seems quite cognitive-complex to code with it (I may be wrong).
I worked with shit-like Java code and i was always able to refactor it in small chunks.
The verbosity of Java is its major strength, but some things added to the language (like default interface implementations, virtual threads) are drawbacks because it create some confusion on basic pattern strategy you can employ with the language.
Which when coupled with the great IDE tooling, graphical debuggers and libraries, is the reason why with exception of Erlang, they remain my main tools.
With the occasional dip into C++ for native libraries.
Great starting place for any language.