Introduction
Java 9 is often remembered for one major feature:
The Java Platform Module System (JPMS).
However, Java 9 introduced many additional enhancements that improved the daily experience of Java developers.
Some of these improvements solved long-standing language limitations.
Others modernized the Java platform itself.
Many of these features quietly became part of everyday enterprise development, even though they rarely receive the same attention as Streams or Lambdas.
In this article, we’ll explore the remaining major features introduced in Java 9 and understand how they fit into modern enterprise applications.
Learning Objectives
By the end of this article, you will be able to:
- Use JShell for rapid experimentation.
- Understand private methods in interfaces.
- Work with the enhanced Process API.
- Simplify resource management.
- Understand multi-release JARs.
- Build custom Java runtimes using
jlink. - Apply these features in enterprise environments.
JShell – The Java REPL
The Problem Before Java 9
Before Java 9, trying a few lines of Java required:
- Create a class.
- Add a
main()method. - Compile.
- Run.
Example:
public class Test {
public static void main(String[] args){
System.out.println("Hello");
}
}
For small experiments, this workflow was cumbersome.
Java 9 Solution
JShell introduced a Read-Evaluate-Print Loop (REPL).
Simply start:
jshell
Now execute Java statements directly.
jshell> int x = 10;
jshell> int y = 20;
jshell> x + y
Output
30
No compilation step.
No main() method.
Enterprise Uses
JShell is useful for:
- Learning Java
- Trying Stream pipelines
- Testing algorithms
- Exploring APIs
- Interview preparation
- Debugging small snippets
It is not intended to replace IDEs or build tools for production applications.
Private Methods in Interfaces
In Java 8, interfaces gained default methods.
However, developers quickly noticed duplicated code.
Example:
public interface PaymentService {
default void process(){
validate();
log();
}
default void refund(){
validate();
log();
}
}
The validation and logging logic often had to be repeated.
Java 9 Solution
Interfaces can now declare private helper methods.
public interface PaymentService {
default void process(){
validate();
}
default void refund(){
validate();
}
private void validate(){
System.out.println("Validation");
}
}
This improves maintainability without exposing implementation details.
Private Static Methods
Java 9 also introduced private static methods.
private static void log(){
System.out.println("Logging");
}
Useful for reusable helper functionality shared across default and static methods.
Enhanced Process API
Before Java 9
Managing operating system processes was limited.
Process process =
Runtime.getRuntime()
.exec("java");
Obtaining process metadata or interacting with child processes was cumbersome.
Java 9 Solution
The new Process API provides much richer capabilities.
ProcessHandle.current();
Retrieve the current process.
Example:
ProcessHandle.current()
.pid();
Returns:
Current Process ID
Process Information
ProcessHandle.current()
.info();
Provides information such as:
- Command
- Start time
- User
- Arguments
Enterprise Uses
Useful for:
- Monitoring
- Container environments
- Diagnostics
- Health checks
- Administrative tools
Try-With-Resources Enhancement
Java 7
BufferedReader reader =
new BufferedReader(...);
try(reader){
...
}
Actually, Java 7 required the resource to be declared inside the try statement:
try (BufferedReader reader = new BufferedReader(...)) {
...
}
Java 9
Existing effectively final variables can be used directly.
BufferedReader reader =
new BufferedReader(...);
try(reader){
...
}
Cleaner.
Less duplication.
Diamond Operator Improvements
Java 9 expanded support for the diamond operator in anonymous inner classes.
new HashMap<>() {
}
This reduced verbosity in some advanced use cases while preserving type safety.
Multi-Release JARs
One of Java 9’s lesser-known but powerful features.
Suppose a library wants to support:
- Java 8
- Java 11
- Java 17
without maintaining three separate JARs.
Java 9 introduced Multi-Release JARs.
Structure:
my-library.jar
META-INF
versions
9
11
17
The JVM automatically loads the implementation appropriate for the running Java version.
Enterprise Uses
Useful for:
- Framework authors
- Library maintainers
- SDK providers
Most business applications consume these libraries rather than creating multi-release JARs themselves.
jlink
Traditional Java deployments included an entire JDK or JRE.
Often, applications required only a subset of Java modules.
Java 9 introduced:
jlink
which creates custom runtime images containing only the required modules.
Example:
Application
+
Required Modules
↓
Custom Runtime Image
Benefits:
- Smaller deployments
- Faster startup
- Reduced attack surface
- Simpler distribution
Enterprise Uses
jlink is particularly valuable for:
- Docker images
- Embedded devices
- Microservices
- Cloud deployments
- Appliance software
Smaller runtime images can reduce container size and deployment time.
Platform Improvements
Java 9 also included many under-the-hood enhancements.
Examples include:
- Improved startup performance.
- Better garbage collection infrastructure.
- Internal API encapsulation.
- Cleaner modular JDK architecture.
Although invisible to application developers, these changes laid the foundation for later Java releases.
Enterprise Migration Strategy
For most enterprise teams upgrading from Java 8:
- Upgrade the JDK.
- Resolve deprecated API usage.
- Continue using the classpath initially.
- Evaluate JPMS when appropriate.
- Take advantage of language and library improvements immediately.
This incremental approach minimizes migration risk.
Common Mistakes
Treating JShell as a Production Tool
JShell is designed for experimentation and learning, not application deployment.
Ignoring jlink
Organizations deploying many microservices can benefit significantly from custom runtime images.
Evaluate whether runtime size and startup improvements justify adoption.
Overusing Private Interface Methods
Private interface methods should support default or static methods, not replace proper service abstractions.
Best Practices
✔ Use JShell for experimentation and learning.
✔ Extract repeated default method logic into private interface methods.
✔ Use the enhanced Process API for diagnostics and monitoring.
✔ Prefer the simplified try-with-resources syntax when applicable.
✔ Consider jlink for containerized deployments.
✔ Use multi-release JARs only when maintaining libraries across multiple Java versions.
Interview Questions
What is JShell?
A Read-Evaluate-Print Loop (REPL) introduced in Java 9 for interactively executing Java code.
Why were private interface methods introduced?
To eliminate duplicated code shared by default and static interface methods.
What problem does jlink solve?
It creates custom Java runtime images containing only the modules required by an application.
What is a Multi-Release JAR?
A JAR that contains version-specific class implementations, allowing the JVM to load the most appropriate implementation for the running Java version.
What changed in try-with-resources in Java 9?
Effectively final resources declared outside the try statement can now be used directly within it.
Summary
Java 9 delivered far more than modules. Features such as JShell, private interface methods, the enhanced Process API, simplified try-with-resources, multi-release JARs, and jlink collectively improved developer productivity and modernized the Java platform.
Many of these enhancements work behind the scenes, but they have become essential building blocks for today’s Java ecosystem, particularly in cloud-native and containerized environments.
With Java 9 complete, we can now move to the next release, where one seemingly small feature dramatically changed how Java developers write local variable declarations.
Coming Up Next
Part 26 – Java 10: Local Variable Type Inference (var) – Cleaner Code Without Losing Type Safety
We’ll examine:
- Why
varwas introduced - How type inference works
- Where
varcan and cannot be used - Readability guidelines
- Enterprise coding standards
- Common anti-patterns
- Performance myths
- Best practices for Spring Boot and microservices