The constant advances in Java and in the JVM have conclusively proved groundless the old canard that “Java is dead.” In fact, the language is advancing at a pace unseen in any other major language today, and given the number of JEPs under active development, the pace is certain to continue for years to come.
Due to the large number of deployed applications still running Java 8 and Java 11, many developers do not have the opportunity to use the new features in their daily work. As a result, Java forums on the web regularly feature questions of the type “I’m leaving a job where I used Java 11. What do I need to know about what happened since then?”
For them and for all Java developers trying to stay up with the changes, this second edition of The Well-Grounded Java Developer is a substantial and authoritative solution. This is not a beginner book, but rather it targets existing Java developers so it avoids introducing language fundamentals. It’s intended for practitioners who want to deepen their understanding of Java and understand the new features.
This 700-page volume is divided into several parts.
The first, consisting of three chapters, reviews in great detail the new features in the language and the JVM since Java 8. The text takes the reader through Java 17, which is the most recent long-term support (LTS) release. One of those chapters is dedicated entirely to modules, and it has the hallmarks of the previous edition: thoughtful advice on when to use modules, low-level details on how they’re implemented, and how to use them, followed by explanations of possible problems you might encounter and the solutions to them. If you were starting from zero on modules, 26 pages later you would be competent to begin using them with full awareness of what to do and why. As to how to build apps with modules, that topic is discussed in detail in chapter 11, which is part of a 130-page treatment on building and deploying Java apps.
After the language update, a four-chapter section follows on low-level details of program execution. The first of these is an extensive introduction to bytecode processing by the JVM. This has the same high quality as articles that have appeared in this magazine by the book’s lead author, Ben Evans. To this are added two chapters on concurrency, which treat the topic from a high level and then explore how the JVM implements concurrency—once again delving into the individual bytecodes. As part of this presentation, a detailed discussion of the Java Memory Model is included.
Because these chapters are segregated into their own section, developers who are more interested in the language details than the JVM innards can skip over this material quickly. However, the final chapter of that section, “Understanding Java Performance,” is important for all Java developers. There, the fundamentals of Java performance, especially the effects of garbage collection, are analyzed in detail. You’ll also find a helpful introduction to Java’s principal performance profiling tool, JDK Flight Recorder.
Then follows a section on building (using Maven and Gradle), deployment to containers (Docker and Kubernetes), and testing Java applications (JUnit, Selenium, and many other tools)—filled with practical, hands-on advice.
The final section of the book goes deeper into advanced topics such as concurrent programming (particularly the fork/join framework), JVM internals, and various future-facing projects the Java team is working on. These projects were previously summarized in the article “Amber, Lambda, Loom, Panama, Valhalla: The major named Java projects.”
The coverage of JVM internals is particularly interesting, as it does not squander time explaining internals basics but goes right to the major changes since the early releases of Java, such as how method handles work, how invokedynamic is executed inside the JVM, and other dense topics.
In this review, I have skipped over one section whose inclusion I find a trifle puzzling in a book on Java: coverage of the Kotlin and Clojure languages. An accompanying section presents functional programming (FP) and how to emulate it in Java. I say “emulate” because all through the explanations, you have the distinct (and, I believe, correct) impression that doing FP in Java is really going against the grain of the language. To be fair, the authors acknowledge in detail the impedance mismatch between Java and FP. In addition, their discussion of FP in the context of the Kotlin and Clojure languages makes more sense, but still the topic feels out of place in a Java book.
The discussion of FP is my only objection to the book, which is otherwise top-to-bottom excellent. The authors are all established Java experts, and Evans and Verburg are Java Champions. The writing is clear, the diagrams are helpful, and the code is illustrative. For all Java developers who need to catch up on what’s happened in the language or want to understand Java from the JVM up, this is the book to use. I highly recommend it.
Andrew Binstock (@platypusguy) is the lead developer on the Jacobin JVM project—a JVM written entirely in Go. He was formerly the editor in chief of Java Magazine, and before that he was the editor of Dr. Dobb’s Journal. Earlier, he cofounded the company behind the open source iText PDF library. He lives in Northern California with his wife, and when he’s not coding, he studies piano.
Previous Post